字符串的模式匹配--BF算法KMP算法
BF算法是基于主串指針回溯,重新與子串進行逐字符進行比較,主串為S什么要進行回溯呢,原因在于模式P中存在相同的字符或者說由字符(串)存在重復(模式的部分匹配性質),設想如果模式P中字符各不相同,主串就S的指針就根本不需要回溯;然而,我們可以發現在主串S與模式發生失配時,主串指針進行回溯會影響效率,因為由于模式S本身字符的部分部分匹配性質,回溯之后,主串S與模式T有些部分比較是沒有必要的,這就是對BF算法所要改進的地方。
BF算法的執行過程:
例:S =″aaaaaaaaaaab″
T =″aaab″
KMP算法的執行過程:
例:S =″ababcabcacbab″
T =″abcac″
經過以上對比,我們可以發現KMP算法的效率要比BF算法的效率高,接下來看一下代碼。
BF算法
BF算法思想
2 .1如果 S[i] = T [j] ,則繼續比較 S 和 T 的下一個字符 ;
2 .2 如果S[i] != T [j],將 i 和 j 回溯 ,準備下一趟比較 ;
否則 ,匹配失敗 ,返回 0;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
KMP算法
KMP的算法中需要用到一個next數組,該數組是用來確定失配后模式串循環變量j回溯的位置的。
next數組的計算
在“aba”中,前綴是真前綴的所有子串的集合,包括“a”、“ab”,除去最后一個字符的剩余字符串叫做真前綴在“aba”中,真前綴“ab”。同理,真后綴就是除去第一個字符的后面全部的字符串。
next就是前綴和后綴中相同的子串的最大長度
例如:
1. 在“aba”中,前綴是“a”,后綴是“a”,那么兩者相同子串最長的就是“a”,相同的子串的最的長度就是1;
2. 在“ababa”中,前綴是“aba”,后綴是“aba”,二者相同子串最長的是“aba”,相同的子串的最的長度就是3;
3. 在“abcabcdabc”中,前綴是“abc”,后綴是“abc”,二者相同子串最長的是“abc”,相同的子串的最的長度就是3;
這里有一點要注意,前綴必須要從頭開始算,后綴要從最后一個數開始算,中間截一段相同字符串是不行的
next數組的計算還有簡單的方法,上述使用最基礎的方法計算的,便于理解
KMP算法思想
2 .1 如果 S[i] = T [j],則繼續比較 S 和 T 的下一個字符 ;
2 .2 如果S[i] != T [j],將 j 向右滑動到 next[ j] 位置 ,即 j = next[j] ;
2 .3 如果 j = 0 ,則將 i 和 j 分別加 1 ,準備下一趟比較;
此處next數組使用一種簡單的方法計算的,此處就不過多解釋了,可以去網上學習一下,網上資源很多
//計算next的值 void getNext(String T, int next[]) {int i;//循環變量int k;next[0] = -1;for (i = 1; T.str[i] != '\0'; ++i) {k = next[i - 1];while (k != -1) {if (T.str[i - 1] == T.str[k]) {next[i] = k + 1;break;} else {k = next[k];}}if (k == -1) {next[i] = 0;}} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
KMP算法的匹配
int KMP(String S, String T, int next[]) {int start = 0;int i = 0;//主串的循環變量int j = 0;//模式串的循環變量while (i < S.length && j < T.length) {if (S.str[i] == T.str[j]) {//若主串和模式串的字符相同,都向后移一位i++;j++;} else {//若失配了,模式串的循環變量就要根據next數組回溯j = next[j];if (j == -1) {i++;j++;//j=-1時,j必須要加1,否則下標越界導致運行出錯}}}if (j == T.length) {//判斷匹配是否成功start = i - T.length + 1;return start;}return -1; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
此外還需要做一些準備工作
#include <stdio.h>#define MAX_SIZE 100typedef struct {//定義一個字符串的結構體char str[MAX_SIZE];int length;//字符串的長度 } String;//初始化 int initString(String *S) {S->length = 0;return 1; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
用main函數測試一下
int main() {String S;//主串String T;//模式串initString(&S);//初始化initString(&T);createStr(&S);//從輸入字符串createStr(&T);printf("----------BF&KMP----------\n");BF(S, T, 0);printf("----------KMP----------\n");int next[T.length];getNext(T, next);for (int i = 0; i < T.length; ++i) {printf("next[%d] = %d\t", i, next[i]);}printf("\n");int start = KMP(S, T, next);printf("\nstart position = %d\n", start);return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
例:
S = “ababcabccabcacbab”
T = “abcac”
運行結果:
總結
以上是生活随笔為你收集整理的字符串的模式匹配--BF算法KMP算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EntityFramework进阶——C
- 下一篇: 浅析CSS选择器