KMP_小白解說

    KMP_歸納詳解 _基礎數據結

  說到kmp,其實是由三個不同的人一起得出來的算法,國內的書像嚴蔚敏寫的那本

太過於數學化,不易於理解,其他blog上好文雖然多但是不適於初學者理解。好,廢話不多說步入正題。

  在講這個之前,先補充一個知識,字符串的前綴,後綴,前後綴公共長度。

Ps(也許有字誤,請把字串自動看成子串,懶得找錯字了)。。。

 

前綴:就是除了字符串的最後一個字符以外的其他的包含第一個字符的排列(順序不可顛倒)

如:”ABCDEFG”={AAB,ABC,ABCD,ABCDE,ABCDEF}ACD這種就不是因爲顛倒順序了

同理,

 

後綴:就是除了字符串的第一個字符以外的其他的包含最後一個字符的排列(順序不可顛倒)

如:”ABCDEFG”={G,FG,EFG,DEFG,CDEFG,BCDEFG}

 

前後綴公共長度:要使這個長度不爲0,首先要滿足的是他們的前後綴有公共部分。

如”ABCDAB”他的前綴,後綴可自己按照上述的方法列出,然後我們得到他的公共部分是

“AB”長度是2

 

以上是補充的知識,下面就是主題了。

KMP,爲什麼需要這個東西呢?

  在解決字符串的問題中,我們也許會需要用到這麼一個東西,給你兩個字符串string a, string b;我們需要找到ba中的位置,就是字串(其他書也叫模式)b在主串a中的位置。

  我們可以很顯而易見的想出差不多on^2)的算法(最壞情況是這個),就是常見的BF方法,這個方法不需要多講很顯而易見,就是每一次去比對,如果不匹配重新從字串的第一個字符去比對。

  上面的BF用了回朔的思想,而改進這個算法,我們就是要把回朔的這一部分去掉,不再需要每一次字串從頭開始,而是通過上一次的比對,如果有相同的部分,直接接到後序去比對。

  上面的廢話可能初學者不是很能理解,不理解的可以不用管,下面會詳細講。

但是需要記住這個公式,(書上並沒有,是各類人的歸納的)

失配之後,字串滑動的位數=已經匹配的長度-對應的部分匹配值(匹配的最後一個字符的next值)

主串:

A

B

C

A

C

A

B

A

B

C

A

B

C

A

C

B

A

B

 

字串:

 

 

現在以上述爲例子,模擬KMP找尋字串在主串的位置

第一步:

 

A

B

A

B

C

A

B

C

A

C

B

A

B

A

找到第一個字串字符與主串第一個比對成功,則兩者同時自增1,進行下一個比對

 

 

第二步:

 

A

B

A

B

C

A

B

C

A

C

B

A

B

A  B   

第三部:

遇到了不匹配的元素,即失配了

(主串s下標設爲i=1開始,子串t下標設爲j=1開始)

A

B

A

B

C

A

B

C

A

C

B

A

B

A  B   C

這裏失配了S[3]!=T[3],根據上面說的公式,我們套進去,匹配的位數(紅字)是2

匹配的最後一個字符是B他的next2】(B的下標)值是1,所以只向前滑動一位

(還不理解next值怎麼來的,繼續往下看)

第四步:

A

B

A

B

C

A

B

C

A

C

B

A

B

   A

還是不匹配,繼續兩個串下標ij1

第五步:

A

B

A

B

C

A

B

C

A

C

B

A

B

       A   B  C   A    C

這裏簡化了匹配步驟,直接匹配到s7】!=t5

這個時候我們的匹配位數(紅色字體)四位,匹配位的最後一個字符的next

next4=1,所以滑動的位數=4-1=3

第五步

A

B

A

B

C

A

B

C

A

C

B

A

B

                   (A)  B   C   A   C

這個時候就已經完成匹配了。

   所以根據上面的總結,KMP的思想就是不去回溯前面的比對,每次比對根據上一次的比對來得到下一次比對的位置,而不是每次從1開始。

上面的內容中,有一點是精華,我們怎麼樣得出next[]數組的值的

也就是每一次失配之後,我們應該從哪個子串的位置開始。

   這個時候就需要用到開頭說的前後綴公共長度了,(此方法書中沒有,乃本人所歸納得出,看過其他大牛的blog還沒有看到和我一樣的方法的)

我說的方法是從下標爲1開始的算法(同嚴蔚敏中的)(blog上大多用下標從0開始)沒差別。

   首先,求next數組,我們得出這麼一個結論,他的值只取決與子串的本身,與主串沒有關係。至於爲什麼?自己多舉幾個例子來看看就知道了,比對的是隻和子串有關。

因此,根據上面的例子中,A B C A C

next[1]=0,(規定next[1]必定爲0,因爲是起始的第一個點)next[2]=1,next[3]=1,next[4]=1

看到這裏,也許會好奇怎麼都是1呢?別急,我在舉一個例子

A B A A B C A C

Next[1]=0,next[2]=1,next[3]=1,next[4]=2,next[5]=2,next[6]=3,next[7]=1,next[8]=2;

原因:當我需要求next[i]的值的時候,我們只需要把第i個字符當作失配的(子串與子串本身匹配),然後我們再判斷1i-1這個長度的字符串中他的公共前綴後綴長度是多少(記爲lenth),然後把的出來的lenth+1,就是當前nexti】的值了,即next[i]=lenth+1;

如例子,next4】因爲ABA他的公共前後長度爲1,再加1,就是2;以此類推。不再枚舉。

理由就是剛纔前面的圖片,只需要把主串也當做子串,用字串自己匹配自己,得到他的next值。相同的部分我們就進行滑動,next就是這個作用。

 

好了上面就是詳情,若不清楚則是我的表達還不到位。

 


#include
#include
using namespace std;
int next[100];
 int get_next(string s){
 	int i=1,j=0;
 	next[1]=0;
 	while(i=t.length()){
			return i-t.size()+1;//書上用的是結構體,我這裏用數組所以a[0]放一個填充(先用string,好寫) 
		}
		else return 0;		 	
 } 
 int main(){
 	string s,t;
 	
 	cin>>s>>t;
 	get_next(t);
 	int position=index_kmp(s,t,1);
 	if(position){//position返回的是下標 
 		cout<<"find it "<

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章