BF kmp以及Gkmp演算法

2022-09-14 09:27:12 字數 3610 閱讀 1382

一、描述:

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 "

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演算法分析:

如果是長度比較短的字串,我們可能能接受那個時間複雜度,但如果字串的長度達到了上百萬,模式串也有十萬,那麼匹配的時間將會是乙個**煩,為此三位學者共同開發了這套快速的字串匹配演算法,根據他們的名字,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 "

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

四、gkmp演算法分析(優化後的kmp演算法)

話說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...