資料結構 字串的模式匹配

2021-09-08 07:35:18 字數 3840 閱讀 5038

什麼叫做模式匹配呢?其實就是看字串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個字串之後的位置。若不存在,則返回...