一、描述:
bf、kmp、gkmp(優化後的kmp)都是基於單個字串(多個字串一般要用到其他演算法,比如說ac自動機)匹配的演算法,不過時間複雜度各有不同,其中bf的時間複雜度為o(n * (m - n + 1)),而kmp演算法的時間複雜度為o(n + m),可見快上了不少,但是這其中確實還是有不足之處,故而推出了優化後的kmp解決了回溯的重複問題。
二、bf演算法分析:
bf(bruteforce)是一種暴力的模式匹配演算法,其基本原理就是列舉每一種可能發生的情況,直到匹配成功,其花費的時間成本是較高的。下面我們來分析一下具體的實現過程。
首先我們有兩個字串,暫且稱第乙個長串為主串,稱第二個短串為匹配串(子串)
t1:abcdac
t2: dac
第一輪匹配(失敗)
第二輪匹配(失敗)
第三輪匹配(失敗)
第四輪匹配(成功,退出匹配)
**實現:
1 #include "三、kmp演算法分析:stdio.h
"2 #include "
string.h"3
intmain()417
if(j ==len2)
18 printf("
match successful in %d\n
",i + 1
);19}20
return0;
21 }
如果是長度比較短的字串,我們可能能接受那個時間複雜度,但如果字串的長度達到了上百萬,模式串也有十萬,那麼匹配的時間將會是乙個**煩,為此三位學者共同開發了這套快速的字串匹配演算法,根據他們的名字,kmp演算法也由此而來。現在讓我們來看看這個演算法到底巧在什麼地方吧!
首先給定兩個字串t1和t2
t1:abaababa
t2:abab
分析可知我們匹配這個字串按照bf匹配的話,如果其中乙個字元不匹配那麼我們需要回到開頭重新匹配,但是kmp演算法充分利用了已知條件----t2,根據t2我們能知道某些一定不能匹配成功的位置,故可以省略,當匹配不成功的時候我們就不需要回到t2的開頭重新匹配了,我們可以回到某個位置匹配,為什麼呢?因為前面的位置你已經走過了呀,你已經知道哪些位置一定不可能成功匹配了,那如何能讓計算機也知道呢?
首先1.我們構建乙個next陣列,儲存不匹配時應該回到的位置(實際上就是該字元上的字首和字尾的最大相似度+1)
2.構建乙個查詢函式,當j不滿足匹配條件時,根據next陣列回溯
雖然構建next陣列時會顯得浪費了時間,但是在後面查詢的時候,將會帶來線性階的回饋。
接下來我們先說說什麼是字首和字尾吧
所謂字首,就是乙個字串除了最後乙個字元不參與組成子串的集合
所謂字尾,就是乙個字串除了第乙個字元不參與組成子串的集合
舉個例子:
abcd 字首有a ab abc
字尾有d cd bcd
解釋了字首和字尾,我們來徒手建立個next陣列把
t1:abaababa
t2:abab
next:0 1 2 3
又因為a沒有字首也沒有字尾,故先給他定為-1,專門處理回溯到子串頭的匹配情況
遍歷到b
字首:a
字尾:b
前字尾相似度為0,故next[1] = 1
遍歷到a
字首:a,ab
字尾:b,ab
前字尾最大相似度為2,故next[2] = 3
遍歷到b
字首:a,ab,aba
字尾:b,ab,bab
前字尾最大相似度為2,故next[3] = 3
next陣列已經構建好了,那麼我麼如何匹配呢?
1.碰到相等的時候i,j同時往後走
2.碰到不相等的時候j開始查詢next陣列回溯,直到走到那些能匹配的位置,或者是返回開頭重新匹配
3.如果j已經走到子串尾後一位了,說明已經匹配成功了
**實現:
1 #include "四、gkmp演算法分析(優化後的kmp演算法)stdio.h
"2 #include "
string.h"3
int next[100];//
next陣列存的值實際上就是這個字元的字首和字尾相似度+1
4void get_next(char *q)515
else
16 k = next[k];//
回溯位置 17}
18}19int kmp(char *p,char *q)
2030
else
31 j =next[j];32}
33if(j ==len2)
34return i -len2;
35return -1;36
}37intmain()
38
話說kmp演算法已經這麼好了,為什麼還需要優化呢?因為kmp會執行不必要的回溯過程
比如說:
aaaaxbaaaaab
aaaaab
當第五個a失配後,會回溯到第四個
第四個很顯然也會失配,會回溯到第三個a
依次類推就會回到開頭了,其實這些過程都是不必要的
所以我們想如果前面的和當前字元相等時,我們的next值是否可以作優化呢?當然是可以的,當當前字元和前面的字元相等時,可以讓當前字元的next值直接等於前面字元得next值,那為什麼可以這樣做呢?我們想啊,如果我當前字元不能滿足匹配,但是我前面的能完成匹配,我是不是可以直接回到上乙個和我前字尾相同的地方去?所以這就是優化的本質!
**實現:
1 #include "五、總結stdio.h
"2 #include "
string.h"3
int nextval[110];4
void get_nextval(char *q)517
else
18 j = nextval[j];//
同kmp一樣的回溯19}
20}21int gkmp(char *p,char *q)
2231
else
32 j = nextval[j];//
回溯33}34
if(j ==len2)
35return i - len2 + 1;36
return -1;37
}38intmain()
39
學習也必須要注重實踐,「紙上談兵終覺淺,絕知此事要躬行」。
模式匹配之(BF KMP演算法)
bf演算法 我們先來看bf 演算法 brute force,最基本的字串匹配演算法 bf演算法的實現思想很簡單 我們可以定義兩個索引值i和j,分別指示主串tag和子串ptn當前正待比較的字元位置,從主串tag的第pos個字元起和子串ptn的第乙個字元比較,若相等,則繼續逐個比較後續字元,否則從主串t...
串的模式演算法 BF KMP
1 編寫完成下列功能的函式 1 建立乙個串 2 實現 bf 模式匹配演算法 3 實現 kmp 模式匹配演算法 4 呼叫建立串函式建立主串和模式串 5 呼叫 bf 演算法輸出匹配結果 6 呼叫 kmp 演算法輸出匹配結果。串的堆順序儲存 typedef structhstring bf演算法 i為主串...
演算法 字串匹配 BF KMP 近似匹配
include includeusing namespace std define maxstr 100 bf 時間o n m int stringmatch bf char str,char pat o m n m str n pat else if pat j 0 找到匹配位置 return i...