字元匹配 真正理解KMP演算法的力量 修正

2021-04-13 02:13:27 字數 2288 閱讀 5662

分析:這道題很自然的想法就是 查詢-回溯,**見 find_1 函式。此演算法最易想到,可是時間複雜度為 o(m*n),其中m,n 分別為s,t的大小。

此類字元匹配有乙個經典演算法,kmp演算法(由knuth、morris、pratt共同提出)。這個演算法非常好的「預處理」了要用於查詢的t.即發現t串的特點,這個特點能夠使查詢時指示s的指標i不回溯,只移動用於指示t的指標j。

next 演算法:

1、next[0]=-1, next[1]=0;令k=next[j],

2、 如果  t[k]=t[j], 則 next[j+1]=k+1;

3、否則令k=next[k],比較 t[ k] ]=t[j],等則next[j+1]=k+1,不等則繼續此步操作。

4、若一直不等,則 next[j+1]=0;

nextval1 演算法:( 在已經求得next的基礎上)

1、令k=next[j], 如果  t[k]==t[j], 令k=next[k],比較t[k] 與 t[j];若等,繼續此操作直到不等的情況。

2、若不能,則next[j]=k;

當然,你應該已經看出其實next 和 nextval1的運算可以合併為乙個函式完成,那就是get_nextval 函式。

在紙上畫出 s, t就可以體會為什麼能夠這樣運算,我的理解是盡量使j值更小,也就是不斷地切分t從0開始的一串(和從t[j-1]倒數相同的一串)。使這串的值最小。

以下是實現的全部**》

find_1 普通實現方法。用count1記錄「基本運算」(比較)次數,**中的次數為56。

find_kmp :kmp演算法,當使用未優化的kmp使 count2 記錄為 36 , 當用優化的kmp演算法時 count2記錄為24. 

// 因為陣列從 0 開始計數,所以**中一些地方使用了-1作為標誌。

#include

using namespace std;

int count1 =0, count2=0;

int find_1( const char s, const char t, int pos )

else  // 這裡的i 和後面放回時i 的值最好用特殊法定,既方便又不易出錯。

++count1;

}if( t[j]=='/0' ) return i-j;  // 這句不能放在while迴圈裡,否則無法判斷找不到匹配字串的情況。

else return -1;  // -1 表示沒有匹配字元}

void get_next( const char t[ ], int next[ ] )  // 未優化的next[ ]

else k=*(next+k);  // 不滿足時,j 不變(因為沒有進入上面的if語句),k 賦值為next[k], 繼續進入if 比較t[j]==t[k].等價於分析時的不等則t[j] == t[ next[k] ];}}

void get_nextval( const char t[ ], int next[ ] )  // 一步實現優化

else k=*(next+k);}}

void get_nextval1( const char t[ ], int next[ ] )  // 在已知next基礎上實現優化

// 若是第乙個位置,則掠過。

k = *(next+j);

while( t[j]==t[k] )  

*(next+j) = k;

++j;  }}

int find_kmp( const char s, const char t,  int pos )

else  j = *(next+j); 

++count2;

}if( t[j]=='/0' ) return i-j;  

else return -1;}

void print( int a, int n )

// kmp.exe has encountered a problem and needs to close.  we are sorry for the inconvenience.

// 可能錯誤原因:陣列越界:因為我用-1 做了一些標記。

真正理解KMP演算法

原帖 所謂kmp演算法,就是判斷乙個模式串是否是乙個字串的子串,通常的演算法當模式串失配後需要回溯原串和模式串,原串從上次開始匹配的下乙個字母開始來匹配模式串的第乙個字母。舉乙個例子,原串為abababcd,模式串為ababcd,如圖1一直從頭開始匹配,當匹配到第5個紅色字母時,發現a和c失配,通常...

typedef的真正理解

首先請看看下面這兩句 typedef int a 10 typedef void p void 如果你能一眼就看出它們的意思,那請不要再往下看了。如果你不太理解,或概念還有些模糊,請繼續往下看吧。下面的東西我就直接把人家的東西粘上去吧。自己敲太慢了。呵呵。原文 摘錄 typedef用來宣告乙個別名,...

控制代碼的真正理解

真理一句話 控制代碼是引用,而不是指標。只能改變對應物件的內容,但不知道物件在哪。以下內容摘取網上資源,如有違反作者版權,請通知。控制代碼是用來標識專案的。它就象我們的姓名一樣,每個人都會有乙個,不同的人的姓名不一樣,但是,也可能有乙個名字和你一樣的人。有一說法是指向指標的指標 專案包括 模組 mo...