目錄概念
簡述kmp演算法原理 **
計算next陣列
kmp演算法 測試
改進kmp演算法簡介
從s中匹配t串,在bf演算法中,通過指標回溯不斷進行匹配,其思想是窮舉。效率很低,但有些串有一定的規律,不需要回溯s串的指標,這就是kmp演算法。
比如 s: aaaaaabkmp演算法是由三個外國人k某、m某、p某三人提出的,所以叫kmp演算法。t: aaab
在進行比較時,如果按照bf演算法,需要進行最後一次才能匹配成功。但是我們發現s和t串前幾位是相同的,不需要重複比較。當然,計算機不會像人這麼敏感,但是能否設計出一種演算法,提高類似這種模式匹配的效率呢?答案是肯定的,這就是kmp演算法。
kmp演算法的核心是針對模式串下手,提取器規律來用於加速匹配過程。
比如,上述匹配過程中s[3]≠t[3],如果按照bf演算法,t指標回溯到t[0],s指標回溯到s[1],繼續進行匹配,s[1]=t[0],s[2]=t[1],這兩個都匹配成功了。嗯,但這個過程有沒有必要呢?
答案是否定的,確實沒必要!
為什麼?
原因在t串身上。
觀察t串可以發現第一次沒有匹配成功的t[3]前面的兩個元素和t串開頭的兩個元素相同,t[0]~t[1]=t[1]~t[2]。而既然我們第一次匹配進行到t[3]了,說明前面的都匹配成功了,即有s[1]=t[1],s[2]=t[2]。
這樣一來,就由上兩個(綠色)式子得到s[1]=t[0],s[2]=t[1]。也就是說,我們根據前面的條件就已經可以推出s[1]=t[0],s[2]=t[1],而不需要將s進行指標回溯再重新匹配了,只需要將t指標回溯到t[2]即可,再進行t[2]和s[3]的比較...
這裡匹配到s和t不需要像bf演算法那樣回溯的核心是什麼?t的t[0]~t[1]=t[1]~t[2]的這個規律,它是s[1]=t[0],s[2]=t[1]的必要條件。也就是說:如果模式串的任意乙個字元的前面的k個字元與開頭k個字元相同,那麼當匹配到該字元不成功時就不需要t指標完全回溯,只需要直接用k作為新的要匹配元素的下標就行。
我們建立乙個陣列next,先掃瞄t串來記錄t串對應位置的k值,後續匹配過程中遇到匹配失敗的時候t串需要回溯到的值k,直接查next表就可以。
這裡用到的一些定義在這篇文章的**裡有。
void gerenext(sqstring t,int *next)
else
k = next[k];//這裡為什麼不是k=-1呢?因為k=-1和k=next[k]是一樣的。
}}
j從頭不停地掃到尾,k則在頭部掃瞄頭部與j匹配的元素個數。本質上其實這也是乙個匹配過程,可以把j掃瞄的當作s串,把k掃瞄的部分當作t串,這也是為什麼k = next[k];而不是直接讓k=-1。
該函式本質上是開頭k個元素組成的串與整個串的模式匹配的過程!匹配結果就儲存在next陣列中(i元素前面k個字元和開頭k個字元匹配成功,儲存為next[i]=k)。k = next[k],本質上是乙個指標回溯,因為j不回溯,所以k不能直接回溯到-1,而是應該回溯到next[k]。這個函式本身就是計算next陣列的,但在計算這個陣列的過程中又用到了這個陣列,可以說是自給自足、自產自銷了。。。關於k=next[k]的詳細的解釋點這裡。如上所示,這種情況下,t串會根據next陣列一直回溯一直到k=-1,但是都是相等的,因此回溯過程是沒必要的!
能不能一步回溯到位呢?
資料結構例程 串的模式匹配(KMP演算法)
本文針對資料結構基礎系列網路課程 4 串中第5課時串的模式匹配 kmp演算法 kmp演算法 include include sqstring.h void getnext sqstring t,int next 由模式串t求出next值 else k next k int kmpindex sqst...
資料結構 串的樸素模式和KMP匹配演算法
一 樸素模式 假設我們要從主串s goodgoogle 中找到子串t google 的位置,步驟如下 i表示主串的當前位置下標,j表示子串的當前位置下標,如上圖在第一輪比較 i 1開始 中j 4和i 4的位置不匹配,接下來就要指標回退,從i 2開始比較,如下 如此反覆直到比較到 i 主串長度 子串長...
資料結構 字串模式匹配的KMP演算法
kmp演算法是模式匹配的一種演算法,他的思想是,當我們進行模式匹配的時候,不用像暴力解法那樣乙個乙個字元去比較,而是從前一串字元的最大前字尾開始匹配,這樣就節省了不少時間 數學推導 假如i代表主串指標,j代表子串指標 如果有 i2 j2 j1 j2 那麼i2 j1,我們在後乙個字元失配 的時候,可以...