數據結構學習之字符串匹配算法(BF||KMP)
阿新 • • 發佈:2019-04-23
優秀代碼 esp 數組 得到 最大 寫法 知識 好玩 lar 顯然前4個字符串滿足 ab=ab 也就是\[t_{0}t_{1}=t_{2}t_{3}\] 當你去用模式串去匹配串
數據結構學習之字符串匹配算法(BF||KMP)
0x1 實驗目的
? 通過實驗深入了解字符串常用的匹配算法(BF暴力匹配、KMP、優化KMP算法)思想。
0x2 實驗要求
? 編寫出BF暴力匹配、KMP、優化KMP的代碼模型
0x2 代碼
0x2.1.1 BF暴力匹配
#include <iostream> #include <string> using namespace std; int BF1(string s1,string s2) { int len=s2.length(); for(int i=0;i<s1.length();i++) { int n=len; int j=i; while(n) { //cout<< s1[j] <<endl; if(s1[j++] != s2[len-n]) break; n--; } if(n==0) return i+1; } return -1; } int BF2(string s1,string s2) { int i=0; int j=0; while(i<s1.length() && j<s2.length()) { if(s1[i]==s2[j]) { i++; j++; }else { i=i-j+1; j=0; } } if(j>=s2.length()) return (i-j+1); else return -1; } int main() { string s1="asfasgasgsd"; string s2="asg"; cout<< BF1(s1,s2) <<endl; cout<< BF2(s1,s2) <<endl; return 0; }
0x2.1.2 結果
?
0x2.1.3 體會
? 我寫了兩種,一開始我沒看書自己意淫了第一種出來,代碼不夠書本簡潔,本著向優秀代碼學習的精神,還有對應對應下面KMP的匹配過程,第二種寫法更有益於學習。過程主要是,while(i<s.length() && j<t.length())
來判斷退出,其中跟kmp不同的是,i需要i-j+1
,j=0
回溯,該算法的時間復雜度0(n*m)。
0x2.2 KMP || KMP優化
#include <iostream> #include <string> #define maxsize 200+7 using namespace std; int next[maxsize]; int nextval[maxsize]; void GetNext(string s,int next[]) { int j=0,k=-1; next[0]=-1; while(j<s.length()-1) //因為數組下標最大是s1.length()-1,下面是j++故j可以到達最大值 { if(k==-1 || s[j]==s[k]) { j++,k++; next[j]=k; }else { k=next[k]; } } } void GetNextVal(string s,int nextval[]) { int j=0,k=-1; nextval[0]=-1; while(j<s.length()-1) { if(k==-1 || s[j]==s[k]) { j++,k++; if(s[j]!=s[k]) nextval[j]=k; else nextval[j]=nextval[k]; }else { k=nextval[k]; } } } //KMP優化 int KMPIndex1(string s,string t) { int i=0,j=0; int next[maxsize]; GetNext(t,next); while(i<s.length() && j<t.length()) { if(j==-1 || s[i]==t[j]) { i++,j++; }else { j=next[j]; } } if(j>=t.length()) return(i-t.length()); else return -1; } //KMP優化 int KMPIndex2(string s,string t) { int i=0,j=0; int nextval[maxsize]; GetNextVal(t,nextval); while(i<s.length() && j<t.length()) { if(j==-1 || s[i]==t[j]) { i++,j++; }else { j=nextval[j]; } } if(j>=t.length()) return(i-t.length()); else return -1; } int main() { string s="aaaaab"; string t="aaab"; cout<< KMPIndex1(s,t) <<endl; cout<< KMPIndex2(s,t) <<endl; return 0; }
0x2.2.1 結果
?
0x2.2.2 體會
? kmp算法主要思想是利用模式串自身的特點,避免主串的回溯過程,同時通過next數組,也減少了模式串的回溯長度。
首先是定義:
\[
next[j]=\left\{\begin{matrix}-1 \qquad 當j=0時
\\MAX \left \{ k|0<k<j\ 且 \ t_{0}t_{1}\cdots t_{k-1} = t_{j-k}t_{j-k+1}\cdots t_{j-1}\right \} \ 當此集合非空時
\\ 0 \qquad 其他情況
\end{matrix}\right.
\]
主要思想是:
? 比如一個模式串 ababb
ababaababb
的時候可以發現\[t_{4} \neq s_{4}\],這個時候就直接可以跳轉到 \[s_{2}\] 開始 而不是從\[s_{1}\]開始,關於這個證明其實也很簡單,如下:
? aba \[\neq\] bab 然後你發現這裏了沒有,從\[s_{1}\]開始其實就是從bab開始很明顯就是不等,其實kmp就是這種規律,找出最大長度的前後綴,那麽就確定了這個模式串滑動的長度,說的更簡單點就是模式串包含了主串的信息,模式串跟主串的比較就可以轉換為模式串跟自己的比較,就像上面的例子,通過反證法可以得到移動<next[j]的話必定會不想等。
代碼重點是:
//初始化
next[0]=-1;
int j=0,k=-1;
while(j<s.length()-1)
{
if(k==-1 || s[j]==s[k])
{
j++,k++;
next[j]=k; //重點
}else
{
k=next[k]; //重點 abdbabc 顯然c -> ab開頭的兩個字符,d不等於c,那麽只能從a=c這裏去比較了next[2]=0
}
}
0x3 最近學習總結
最近感覺自己特別浪,要學的東西還有很多,平時效率也好低,數據結構的作業也拖了好久,以前都是4天一次,這次竟然拖了那麽10多天,最近要抓緊空閑時間去補回來了,下篇寫一些遞歸的題目,介紹一些好玩的知識點。
數據結構學習之字符串匹配算法(BF||KMP)