標籤:長度 包括 電腦 尾碼 rac jpg str nal 查表
字串匹配是電腦的基本任務之中的一個。
舉例來說,有一個字串"BBC ABCDAB ABCDABCDABDE"。我想知道。裡面是否包括還有一個字串"ABCDABD"?
很多演算法能夠完畢這個任務,Knuth-Morris-Pratt演算法(簡稱KMP)是最經常使用的之中的一個。它以三個發明者命名。起頭的那個K就是著名科學家Donald Knuth。
這樣的演算法不太easy理解。網上有非常多
q=Knuth-Morris-Pratt+algorithm" target="_blank">解釋。但讀起來都非常費勁。直到讀到Jake Boxer的文章。我才真正理解這樣的演算法。
以下,我用自己的語言,試圖寫一篇比較好懂的KMP演算法解釋。
1.
首先,字串"BBC ABCDAB ABCDABCDABDE"的第一個字元與搜尋字詞"ABCDABD"的第一個字元。進行比較。由於B與A不匹配。所以搜尋字詞後移一位。
2.
由於B與A不匹配,搜尋字詞再往後移。
3.
就這樣,直到字串有一個字元。與搜尋字詞的第一個字元同樣為止。
4.
接著比較字串和搜尋字詞的下一個字元。還是同樣。
5.
直到字串有一個字元。與搜尋字詞相應的字元不同樣為止。
6.
這時,最自然的反應是,將搜尋字詞整個後移一位,再從頭逐個比較。這樣做儘管可行,可是效率非常差,由於你要把"搜尋位置"移到已經比較過的位置,重比一遍。
7.
一個基本事實是,當空格與D不匹配時,你事實上知道前面六個字元是"ABCDAB"。KMP演算法的想法是。設法利用這個已知資訊。不要把"搜尋位置"移回已經比較過的位置,繼續把它向後移。這樣就提高了效率。
8.
怎麼做到這一點呢?能夠針對搜尋字詞,算出一張《部分匹配表》(Partial Match Table)。這張表是怎樣產生的,後面再介紹。這裡僅僅要會用就能夠了。
9.
已知空格與D不匹配時,前面六個字元"ABCDAB"是匹配的。
查表可知。最後一個匹配字元B相應的"部分匹配值"為2。因此依照以下的公式算出向後移動的位元:
移動位元 = 已匹配的字元數 - 相應的部分匹配值
由於 6 - 2 等於4,所以將搜尋字詞向後移動4位。
10.
由於空格與C不匹配,搜尋字詞還要繼續往後移。這時,已匹配的字元數為2("AB"),相應的"部分匹配值"為0。所以,移動位元 = 2 - 0,結果為 2。於是將搜尋字詞向後移2位。
11.
由於空格與A不匹配,繼續後移一位。
12.
逐位比較,直到發現C與D不匹配。於是。移動位元 = 6 - 2,繼續將搜尋字詞向後移動4位。
13.
逐位比較,直到搜尋字詞的最後一位,發現全然匹配,於是搜尋完畢。
假設還要繼續搜尋(即找出所有匹配)。移動位元 = 7 - 0,再將搜尋字詞向後移動7位,這裡就不再反覆了。
14.
以下介紹《部分匹配表》是怎樣產生的。
首先。要瞭解兩個概念:"首碼"和"尾碼"。 "首碼"指除了最後一個字元以外,一個字串的所有頭部組合;"尾碼"指除了第一個字元以外。一個字串的所有尾部組合。
15.
"部分匹配值"就是"首碼"和"尾碼"的最長的共同擁有元素的長度。以"ABCDABD"為例,
- "A"的首碼和尾碼都為空白集,共同擁有元素的長度為0;
- "AB"的首碼為[A]。尾碼為[B],共同擁有元素的長度為0。
- "ABC"的首碼為[A, AB]。尾碼為[BC, C]。共同擁有元素的長度0;
- "ABCD"的首碼為[A, AB, ABC],尾碼為[BCD, CD, D],共同擁有元素的長度為0;
- "ABCDA"的首碼為[A, AB, ABC, ABCD]。尾碼為[BCDA, CDA, DA, A],共同擁有元素為"A",長度為1;
- "ABCDAB"的首碼為[A, AB, ABC, ABCD, ABCDA],尾碼為[BCDAB, CDAB, DAB, AB, B],共同擁有元素為"AB",長度為2。
- "ABCDABD"的首碼為[A, AB, ABC, ABCD, ABCDA, ABCDAB]。尾碼為[BCDABD, CDABD, DABD, ABD, BD, D],共同擁有元素的長度為0。
16.
"部分匹配"的實質是,有時候。字串頭部和尾部會有反覆。
比方,"ABCDAB"之中有兩個"AB"。那麼它的"部分匹配值"就是2("AB"的長度)。
搜尋字詞移動的時候。第一個"AB"向後移動4位(字串長度-部分匹配值),就能夠來到第二個"AB"的位置。
“KMP的演算法流程:
- 如果如今文本串S匹配到 i 位置。模式串P匹配到 j 位置
- 假設j = -1,或者當前字元匹配成功(即S[i] == P[j]),都令i++,j++,繼續匹配下一個字元。
- 假設j != -1,且當前字元匹配失敗(即S[i] != P[j])。則令 i 不變。j = next[j]。此舉意味著失配時,模式串P相對於文本串S向右移動了j - next [j] 位。”
我們發現假設某個字元匹配成功。模式串首字元的位置保持不動,不過i++、j++;假設匹配失配。i 不變(即 i 不回溯),模式串會跳過匹配過的next [j]個字元。整個演算法最壞的情況是,當模式串首字元位於i - j的位置時才匹配成功,演算法結束。
所以。假設文本串的長度為n。模式串的長度為m。那麼匹配過程的時間複雜度為O(n),算上計算next的O(m)時間。KMP的總體時間複雜度為O(m + n)。
很多其它瞭解能夠查看July解說:http://blog.csdn.net/v_july_v/article/details/7041827
字串匹配的KMP演算法