分析:這道題很自然的想法就是 查詢-回溯,**見 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...