字串模式匹配KMP演算法

2021-06-20 05:11:56 字數 3562 閱讀 8919

字串模式匹配指的是,找出特定的模式串在乙個較長的字串中出現的位置。

很直觀的可以寫出下面的**,來找出模式串在乙個長字串中出現的位置。

1:  

/*

2:  

樸素的模式匹配演算法

3:  

功能:字串的模式匹配

4:  

引數:

5:  

s:目標串

6:  

p:模式串

7:  

pos:開發匹配的位置

8:  

返回值:

9:  

匹配成功,返回模式串在目標串的其實位置

10:  

匹配不成功,返回-1

11:  

*/

12:  

int match(const

char * s ,const

char * p,int pos)else

23:      }
24:
25:  

if(p[j] == '\0')

26:  

return i - j ;

27:  

else

28:  

return -1 ;

29:  }
上面的**,s就是目標串,p是模式串,pos指定從s的什麼位置開始匹配p。其實現思想也很簡單:

當s[i] == p[j]時,目標串和模式串的指標都向後移動一位,進行匹配。而當s[i] != p[j]時,即匹配不成功時,將目標串和模式串的指標同時回溯,j = 0 而目標串的指標i則回溯到這輪開始的下乙個位置。

樸素的模式匹配的演算法複雜度是o( (n-m+1) * m)  n為目標串的長度,m為模式串長度。

從其實現思想上可以很容易的看出,造成該演算法低效的地方是在,匹配不成功時主串和模式串的指標回溯上。

有沒有一種演算法,當模式串和主串的匹配不成功時,不用進行指標的回溯,直接進行下一輪的匹配?

在樸素的字串模式匹配演算法上,當遇到主串和模式串的字元不能匹配成功時,不論已經匹配了多少字元都要進行指標回溯,再開始下一輪的匹配。

這樣效率是十分的低下的。kmp演算法,是在樸素的模式匹配演算法的基礎上,實現了匹配不成功時,不對主串指標進行回溯,使模式匹配的時間複雜度

降低為:o(n + m)。

對kmp演算法的理解,在網上查詢了不少資料,也看了演算法導論上的描述,一直是一知半解。有次閒暇之餘,想像著將模式串、主串都看著是條直線,進行了下推導,才恍然大悟。

kmp演算法的核心思想是,在s[i] 和 p[j]不匹配時,不對主串進行指標回溯,而是在模式串中p中尋找k,用s[i] 和 p[k]進行下一輪的匹配。

在這裡,將主串 s 和模式串 p 都看成是一條直線,故而在s[i] 和 p[j] 匹配不成共時,有如下情形:

圖1 s[i] 和 p[j] 匹配不成功

即是:p[1…j-1] == s[i-j+1,…,i-1].

p[j] 和 s[i] 不匹配,現在要在模式串p[1,…,j-1]確定乙個位置k(1<= k < j-1),用p[k]和s[i]進行下一輪匹配,那麼k必須要滿足以下條件:

p[1,..,k-1] == s[i-k+1, … , i-1] .

將模式串和主串都看著一條直線,那麼就有下圖:

圖2  使用p[k]和s[i]進行下一輪匹配

由於 1<= k < j-1,那麼將兩圖合併起來會有什麼效果呢?

從上圖可以看出,當s[i]和p[j]匹配不成功時,假如能用p[k]和s[i]進行下一輪匹配,則有:

s[i-k+1], … , i-1] == p[j-k+1,…,j-1] == p[1,…,k-1] 。

就是說,當s[i] 和 p[j] 匹配不成功時,最對主串不進行指標回溯,而是用p[k]和s[i]進行匹配時,k必須滿足以下條件:

p[1,…,k-1] == p[j-k+1, … , j-1]。

kmp演算法的是對匹配的模式匹配演算法的改進,在s[i]和p[j]匹配不成功時,不是對主串進行指標的回溯,而是在p[1,…,j-1]中,尋找乙個p[k],

用s[i]和p[k]進行下一輪的匹配。其實現的最大問題就是如何的根據p[1,…,j-1]來求出p[k]。

在kmp演算法的實現中,使用乙個輔助陣列next,使用該陣列儲存p[j]匹配不成功時,要進行下一輪匹配的k的值.即是當s[i] 和 p[j]匹配不成功時,

用p[ next[j] ]來和s[i]進行下一輪匹配,k = next[j] .

對陣列next 的求解,可以goolge到不少的方法,這裡使用最簡單的遞推的方法:

首先假定next[0] = –1,那麼當next[j] = k時,就有:p[0,…,j-1] == p[j-k+1,…,j-1]。

這時,若有p[k] = p[j] ,則p[0,….,k] = p[j-k+1,..,j-1,j],從而就有next[j+1] = next[j] + 1 = k +1 .

若p[k] != p[j] ,可以看著模式串對自身進行匹配的問題,即當匹配失敗的時候,k值如何確定,k = next [k] .

求陣列next[ ]的實現如下:

/*

kmp進行模式匹配的輔助函式

模式串和主串匹配不成功時,下次和主串進行匹配的模式串的位置

*/void continue_prefix_function(const

char * p , int * next) else }}

知道了當模式串和主串匹配不成功時,下乙個和主串匹配的字元在模式串中的位置,在樸素的模式匹配的基礎上很容易的寫出kmp演算法的**如下:

/*

運用kmp演算法的字串模式匹配

在主串和模式串匹配不成功時,不對主串指標進行回溯,

例如用next[j],來指定下一次和主串進行匹配的模式串的位置

*/int match_kmp(const

char * s ,const

char * p,int pos) else

else }}

if(p[j] == '\0')

return i - j ;

else

return -1 ;

}

一直想寫篇文章總結下自己對kmp演算法的理解,拖拉很久,終於算完成了。不過,寫篇文章真是不容易啊,花了將近2個小時,也不知道表達清楚木有。文章出處:

字串模式匹配KMP演算法

next的值去改變每次匹配的位置 注意 字串的儲存最好用字元陣列,然後用字元輸入的形式,保證正確!利用求模式串的next值來分析遍歷,可以在不改變主串i的值的基礎上,只改變next j 的下標來遍歷 next j include include using namespace std void ge...

字串模式匹配KMP演算法

字串模式匹配指的是,找出特定的模式串在乙個較長的字串中出現的位置。很直觀的可以寫出下面的 來找出模式串在乙個長字串中出現的位置。1 2 樸素的模式匹配演算法 3 功能 字串的模式匹配 4 引數 5 s 目標串 6 p 模式串 7 pos 開發匹配的位置 8 返回值 9 匹配成功,返回模式串在目標串的...

演算法 字串模式匹配KMP

定位字串p在字串s中的位置,可以稱作字串的模式匹配 int search char const int,char const int 查詢出模式串patn在主串src中第一次出現的位置 plen為模式串的長度 返回patn在src中出現的位置,當src中並沒有patn時,返回 1 int searc...