什麼叫做模式匹配呢?其實就是看字串s中是否有子串t,那麼t就叫匹配串。
我們平時查詢方式是逐個匹配,那麼時間複雜度就是o(n*m).
比如s=』abcabde』,t=』abd』
那麼比較的時候s[1]=t[1],所以接下來比較s[2]和t[2],結果s[2]=t[2],那麼接下來就比較s[3]和t[3],這一次比較匹配不上。
然後就是普通匹配方法比較耗時的地方:比較s[2]和t[1]繼續上面那樣的流程。這樣就可以看到,最壞的情況需要比較o(n*m)次。
畫一下匹配過程:
1 abcabde
abd 匹配失敗
2 abcabde
a 匹配失敗
3 abcabde
a 匹配失敗
4 abcabde
abd 匹配成功
我們看到比了4次。那麼怎麼用程式來實現呢?
function commonindex(const sub,dest:string):integer ;
var i,j:integer;
len1,len2:integer;
begin
len1:=length(sub);
len2:=length(dest);
result:=0;
if len1>len2 then
exit;
j:=1;
i:=1;
//判斷過程
while (i<= len2 - len1 + 1)and(j <= len1) do
if dest[j] = sub[i] then
begin
inc(i);
inc(j);
endelse
begin
j:=1; //sub回溯
i:=i-j+2; //dest回溯
end;
//判斷是否查詢成功
if j = len1 then
result:=i-j+1;
end;
接下來看看c怎麼實現的:
int commonindex(char* sub,char* dest)else
}//endwhile
if (!sub[j])
return i-j+1;
else
return 0;
}
就像上面注釋那樣,每次匹配失敗的話,都需要把兩個字串都回溯,所以這裡就必要浪費時間了。
整個演算法的時間複雜度是o(m*n)
我們再回來看看上面的匹配過程。
1 abcabde
abd 匹配失敗
在匹配到c和d這裡,我們發現不用再去比較b和a 以及c和a了,因為肯定不能匹配。所以現在我們只需要回溯sub字串。
看看改進後的匹配過程:
1 abcabde
abd 匹配失敗
2 abcabde
abd 匹配成功
但是sub每次匹配失敗後回溯多少呢?這就是這個kmp演算法裡面精髓的地方。
我們先看看**吧!
function kmpindex(const sub,dest:string):integer;
var i,j:integer;
len1,len2:integer;
next:array of integer;
procedure makenext;//自過程生產next表
begin
i:=1;
j:=0;
next[1]:=0;
while i<=len1 do
if(j=0)or (sub[i]=sub[j])then
begin
inc(i);
inc(j);
next[i]:=j;
endelse
j:=next[j];
end;
begin
len1:=length(sub);
len2:=length(dest);
result:=0;
if len1>len2 then
exit;
setlength(next,len1 + 1); //動態陣列是從0開始的,我們要從1開始,所以這裡+1,多乙個元素
//生成sub的回溯表。
makenext;
tryi:=1;
j:=1;
while (i<=len1)and(j<=len2) do
if (i=0)or(sub[i] = dest[j]) then //匹配成功
begin
inc(i);
inc(j);
endelse
i:=next[i]; //失敗,只有sub回溯一下
if i > len1 then
result:=j - i + 1;
finally
setlength(next,0);
end;
end;
那麼c的**會是怎麼樣呢?
int kmpindex(char* sub,char* dest){
int len = 0;
//計算sub的長度
for(;sub[len];++len);
//動態分配next陣列
int* next = (int*)malloc(len *sizeof(int));
//生成next陣列
int i = 0,k = -1;
//*(next++) = 0;
next[0] = -1;
while (i我們看看時間複雜度吧。理論來說應該大於o(n+m),小於o(n*m).在實際過程中近似o(n+m).
從上面的**中我們可以看見next的第i個元素是靠比較第i-1個得到的。
while (i如果字元是從1開始的,那麼next[0] = 0,如果字元從0開始的,那麼next[0]=-1;
那麼我們手動來計算一下 'abababd』的next陣列字,假設字串從1開始。
a b a b a b d
0 //第乙個直接等於0
0 1 //第二個要靠第乙個去判斷。第乙個字元為a,對應next[1]值為0,那麼結束比較。next[2]=1
0 1 1 //第三個要靠第二個去判斷。第二個字元為b,對應的k值為1,而第乙個字元是a,由於b不等於a,繼續取第乙個字元a對應的k值,k為0比較結束,next[3]=1;
0 1 1 2 //第四個要靠第三個。第三個字元是a,對應的k值為1,而第乙個字元是a,由於a=a,比較結束next[4]=1+1=2
0 1 1 2 3 //第五個要靠第四個。第四個字元是b,對應k值是2,而第二個字元是b,由於b=b,比較結束next[5]=2+1=3
0 1 1 2 3 4 //同理。第五個字元是a,對應的k值是3,而第三個字元是a,由於a=a,比較結束,所有next[6] = 3+1 = 4;
0 1 1 2 3 4 5 //第六個字元是b,對應的k是4,而第四個字元是b,由於b=b,比較結束,所以next[7] = 4 + 1 = 5;
整個next陣列就是 0 1 1 2 3 4 5
不知道大家對上面這個求的過程看明白了沒有。
當然這個生成next的過程在特殊情況是有錯誤的。所以就有了改進的地方,nextval。這個我們下回再說。有條件的朋友可以自己看看書。
書中自有**屋,書中自有顏如玉。
金錢與女人都出自書本。。。哈哈,難怪古代文人那麼喜歡逛青樓。。。蛋疼。!!
等著我的nextval 謝謝
資料結構 字串 模式匹配
我們先把模式串標出序號 接著把模式串所有字首依次列出來 接下來把每乙個子串相等的字首和字尾的最大長度求出,舉個例子 abaab 觀察子串,前字尾ab相同,因此返回2 5.依次類推,我們可以得到每乙個子串對應的一組序列 當時這組資料並不是所要求的next陣列,可以將其稱為部分匹配值表,相應c 如下 獲...
資料結構之字串的模式匹配
字串的模式匹配問題 一共有兩種演算法,1.樸素模式匹配演算法。舉例而言 尋找從s goodgoogle 中找到v google 這個子串 我們一般需要以下的步驟 1 從主串的第乙個字元開始,s與 v中的字元逐一比較,可以發現前三個匹配成功而第四個沒有匹配成功 豎線代表成功,折現代表失敗 2 主串的開...
資料結構 字串匹配
演算法 如下,包括暴力匹配和kmp演算法。參考 include stringmatching.h stringmatching stringmatching void stringmatching stringmatching void 返回子串t在主串s中第pos個字串之後的位置。若不存在,則返回...