在寫程式時,我們常常會用到從乙個字串找出子串的位置。
比如,在某個句子快速找到某個你感興趣的詞:「csscsdn」中找到csdn
以下是查詢演算法,注意:下標為1代表第乙個位置,以此類推,跟陣列不同
一、樸素模式匹配
樸素模式匹配是從第乙個字元開始,依次向後匹配,這裡我們假設游標起始點為1
c s s c s d n
|| || ?
c s d n
當i(主串的游標) = 3,j(子串的游標) = 3時,字元出現了不等,於是i回到2,j回到1
c s s c s d n
?c s d n
直到c s s c s d n
|| || || ||
c s d n
樸素模式匹配最大的問題就是i值回溯,如果碰到當子串的前面都與主串匹配,只有最後乙個字元不同,而這個子串又在主串的末尾時,j值會每次遍歷整個字串,i值會每次回溯
000...共n個0...0001
0...共m個0...01
當出現上面的情況時,會發生最壞的情況,此時時間複雜度為o((n-m+1)*m)
二、kmp演算法
後來有三位前輩(knuth、pratt和morris)發布了乙個大大避免重複遍歷的演算法,簡稱kmp演算法
1、c s d c s d n
?c s d n
2、c s d c s d n
?c s d n
3、c s d c s d n
?c s d n
可以看到,其實2和3步驟完全是沒有必要的,因為在第一次比較時csd都是一樣的,所以主串中的第乙個s必然不等於字串的c,主串中的第乙個d也必然不等於子串中的c
再看另一種情況
1、c s c s c s b n
?c s c s d n
2、c s c s c s b n
?c s c s d n
3、c s c s c s b n
||c s c s d n
4、c s c s c s b n
|| ||
c s c s d n
5、c s c s c s b n
|| || ||
c s c s d n
6、c s c s c s b n
|| || || ||
c s c s d n
7、c s c s c s b n
|| || || || ?
c s c s d n
可以看出,2、3、4步是沒有必要的,2步沒必要跟上面的情況一致,而3、4沒必要,是因為子串在1中已經知道前4個字元都與主串是一樣的了,既然即主串中第三和第四個位置上的字元與子串
第三和第四個位置上的字元是一樣的,而子串第三和第四個位置上的字元又與子串第一和第二個位置上的字元一樣,那子串中第一和第二個位置上的字元必然與主串中第三和第四個位置上的字元一樣,所以是不需要3、4步驟的
綜上,我們可以總結出兩點:1、主串中的i是不需要回溯的,子串中的j需要回溯;2、子串中的j回溯的位置,跟子串字元的重複有關係
接下來,我們需要找出子串字元的重複關係,通過上面c s c s c s b n與 c s c s d n的查詢,我們可以看到,如果省略步驟3和4,當i = 5時,是與j = 3的字元來比較的,
我們把子串j值的變化用乙個next陣列來表示:
j: 1 2 3 4 5 6
t: c s c s d n
next: 0 1 1 2 3 1
下面來說說為什麼這麼表示,首先,next[1] = 0,是為了簡化判斷,這個我們稍後再說;然後看next[5] = 3,之所以等於3,是因為在j = 5不匹配時,我們無需讓j回溯到1,只需要回溯到3即可,因為t[1] = t[3],t[2] = t[4],可以推出next[j] = max(當此集合不為空的時候,這裡->代表下標),實際上,k就是子串開頭字元重複的個數加1
next陣列的生成**,注意:t[0]表示子串的長度:
[cpp]view plain
copy
void
get_next(
char
*t,
int*next) else
} }
有了next陣列,kmp實現**就出來了,注意:
t[0]表示子串的長度,s[0]表示主串的長度
:[cpp]view plain
copy
intindex_kmp(
char
*s,
char
*t,
intpos) else
} if(j > t[0])
return
i - t[0];
else
return
0;
}
現在我們看到next[1]為0可以簡化判斷j是否回溯到開頭的**,並且方便的實現從j=1開始向後匹配
KMP模式匹配演算法(1)
在寫程式時,我們常常會用到從乙個字串找出子串的位置。比如,在某個句子快速找到某個你感興趣的詞 csscsdn 中找到csdn 以下是查詢演算法,注意 下標為1代表第乙個位置,以此類推,跟陣列不同 一 樸素模式匹配 樸素模式匹配是從第乙個字元開始,依次向後匹配,這裡我們假設游標起始點為1 c s s ...
模式匹配 KMP演算法
字串匹配演算法 include includeusing namespace std define ok 1 define error 0 define overflow 2 typedef int status define maxstrlen 255 使用者可在255以內定義最長串長 typed...
模式匹配KMP演算法
前些日子在為目前該學習什麼而苦惱,就問了一下已經從事多年軟體開發的表哥,他說乙個程式設計師要走的遠,就要學好資料結構和演算法,於是我就重新開始學習資料結構和演算法了 拿起以前上過的資料結構看,看到第四章串的模式匹配時,頗感興趣,就寫了一下程式,實踐了一下。感覺還蠻爽,於是就把以下幾個重要的函式放在此...