今天來記錄一下,關於字元匹配的kmp演算法。
給定字串text和pattern,需要判斷字串pattern是否為test的子串。pattern一般稱為模式串,text為文字串。若匹配成功,則讓函式返回,匹配開始處的下標,否則,返回-1。
假設有乙個字串s,它以i號位作為結尾的子串就是s[1…i]。對該字串來說,長度為 k+1 的字首和字尾分別是 s[0…k] 和 s[i - k…i] 。現在定義乙個 next 陣列,其中 next[i] 表示使子串 s[0…i] 的字首 s[0…k] 等於字尾 s[i-k…i] 的最大的 k (注意:字首字尾可以部分重合,但不能是 s[0…i] 本身),如果找不到相等的前字尾,就令next[i] = -1。顯然 next[i] 就是所求最長相等前字尾中字首的最後一位的下標。
//對於next陣列而言,next[0]總是等於-1,因為對第一位來說,其不存在公共前字尾,而又為了其他位比較時,從上一位next[0]多一位的1開始比較。
void
getnext
(char pattern,
int m)
if(pattern[i]
== pattern[j +1]
) next[i]
= j;
//每次讓j記錄上一字元的next值
}return
;}
//對於該演算法,只有pattern上的指向在不斷由於i的更新改變
intkmp
(char text,
char pattern,
int n,
int m)
if(text[i]
== pattern[j +1]
)if(j == m -1)
}return-1
;//不匹配返回-1
}
上述**與求解next的**驚人的相似,其實求解next陣列的過程就是模式串pattern進行自我匹配的過程。
計算mext陣列的時間複雜度為o(m),匹配過程的時間複雜度為o(n),故kmp演算法的時間複雜度為o(m + n)。
上述**中關於匹配中回退,從匹配的角度看,每次匹配不成功,next[j]表示當模式串的 j + 1 位失配的時候,j應當退到的位置,仔細思考,每次我們退的時候,j會進行多次無意義的回退,即他總是回到 next[j] 的位置,但全然不管 pattern[j + 1] == pattern[next[j] + 1] 的情況,即這一次回退之後還是匹配不上。要讓 next[j] 進行改變,一步回退到恰當的位置,就要對 next 陣列進行變化。優化後 nextval 陣列的含義為當模式串 pattern 的 i+1 位發生失配的時候,i 應當回退到的最佳位置。
void
getnextval
(char pattern,
int m)
if(s[i]
== s[j +1]
)if(j ==-1
|| s[i +1]
!= s[j +1]
)else
}return
;}
注:nextval只是跳過了無意義的匹配,並不會導致漏解,而由nextval的含義,getnextval 和 kmp中的 while 都可以換成 if ,因為最多隻會執行一次。 經典演算法之KMP演算法及其優化
kmp演算法的具體分析見 author s email wardseptember gmail.com date 2017.12.18 kmp演算法 include include using namespace std define maxsize 50 void getnext char sub...
C 實現KMP演算法及其優化
自己寫了乙個簡潔版本,加注釋。第乙個函式是得到kmp的next陣列。1 設定next的第乙個值為 1。2 遍歷剩下的t串 3 t串前後比較,相等就在next中對應位置加1 4 不等,就回溯 t串中等價位置 void getnext string t,int next else j next j 第二...
模式匹配(kmp)及其優化
對於兩個字串s,p。想要判斷s串中是否有模式串p,正常的思路是依次遍歷,看是否能夠匹配成功。但實際上這種有回溯的模式匹配效率往往不高,故有此無回溯模式匹配演算法 乙個直接按照定義計算字首函式的演算法流程 在乙個迴圈中以 的順序計算字首函式 的值 被賦值為 為了計算當前的字首函式值 我們令變數 從最大...