BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是將目標串S的第一個字符與模式串T的第一個字符進行匹配,若相等,則繼續比較S的第二個字符和 T的第二個字符;若不相等,則比較S的第二個字符和T的第一個字符,依次比較下去,直到得出最后的匹配結果。
BF算法實現:
1 int BF(char S[],char T[],int pos) 2 {//c從第pos位開始搜索匹配 3 int i=pos,j=0; 4 while(S[i+j]!='\0'&&T[j]!='\0') 5 { 6 if(S[i+j]==T[j]) 7 j++; 8 else 9 { 10 i++; 11 j=0; 12 } 13 } 14 if(T[j]=='\0') 15 return i+1; 16 else 17 return -1; 18 }
BF算法比較直接,是一種蠻力算法,該算法最壞情況下要進行M*(N-M+1)次比較,時間復雜度為O(M*N),下面來看一個效率非常高的字符串匹配算法,即KMP算法。
KMP算法完成的任務是:給定兩個字符串S和T,長度分別為n和m,判斷f是否在S中出現,如果出現則返回出現的位置。常規方法是遍歷a的每一個位置,然后從該位置開始和b進行匹配,但是這種方法的復雜度是O(nm)。kmp算法通過一個O(m)的預處理,使匹配的復雜度降為O(n+m)。
KMP算法思想:
優化的地方:如果我們知道模式中a和后面的是不相等的,那么第一次比較后,發現后面的的4個字符均對應相等,可見a下次匹配的位置可以直接定位到f了。說明主串對應位置i的回溯是不必要的。這是kmp最基本最關鍵的思想和目標。
由於abc 與后面的abc相等,可以直接得到紅色的部分。而且根據前一次比較的結果,abc就不需要比較了,現在只需從f-a處開始比較即可。說明主串對應位置i的回溯是不必要的。要變化的是模式串中j的位置(j不一定是從1開始的,比如第二個例子)j的變化取決於模式串的前后綴的相似度,例2中abc和abc(靠近x的),前綴為abc,j=4開始執行。
下面我們來看看Next()數組:
定義:
(1)next[0]= -1 意義:任何串的第一個字符的模式值規定為-1。
(2)next[j]= -1 意義:模式串T中下標為j的字符,如果與首字符
相同,且j的前面的1—k個字符與開頭的1—k
個字符不等(或者相等但T[k]==T[j])(1≤k<j< span="">)。
如:T=”abCabCad” 則 next[6]=-1,因T[3]=T[6]
(3)next[j]=k 意義:模式串T中下標為j的字符,如果j的前面k個
字符與開頭的k個字符相等,且T[j] != T[k] (1≤k<j< span="">)。
即T[0]T[1]T[2]。。。T[k-1]==
T[j-k]T[j-k+1]T[j-k+2]…T[j-1]
且T[j] != T[k].(1≤k<j< span="">);
(4) next[j]=0 意義:除(1)(2)(3)的其他情況。
意義:
next 函數值究竟是什么含義,前面說過一些,這里總結。
設在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函數值next[n],
1. next[n]= -1 表示S[m]和T[0]間接比較過了,不相等,下一次比較 S[m+1] 和T[0]
2. next[n]=0 表示比較過程中產生了不相等,下一次比較 S[m] 和T[0]。
3. next[n]= k >0 但k<n, <="" span="">表示,S[m]的前k個字符與T中的開始k個字符已經間接比較相等了,下一次比較S[m]和T[k]相等嗎?
4. 其他值,不可能。
Next()數組求解的實現:
void getNext(const char* pattern,int next[]) { next[0]= -1; int k=-1,j=0; while(pattern[j] != '\0') { if(k!= -1 && pattern[k]!= pattern[j] ) k=next[k]; ++j;++k; if(pattern[k]== pattern[j]) next[j]=next[k]; else next[j]=k; } }
Next()數組求出后,就可以進行字符串匹配了
int KMP(char *s,char* t) { if( !s||!t|| t[0]=='\0' || s[0]=='\0' ) return -1;//空指針或空串,返回-1。 int len=0; const char * c=t; while(*c++!='\0') { ++len; } int *next=new int[len+1]; getNext(t,next); int index=0,i=0,j=0; while(s[i]!='\0' && t[j]!='\0' ) { if(s[i]== t[j]) { ++i; ++j; } else { index += j-next[j]; if(next[j]!=-1) j=next[j]; else { j=0; ++i; } } } delete []next; if(t[j]=='\0') return index; else return -1; }
寫到這,KMP算法介紹的也差不多了,關於KMP算法優化,待續。。。。