KMP算法中NEXT数组的作用以及代码实现
在http://blog.csdn.net/u012613903/article/details/79004094中寫到了如何手工去求一個NEXT數組,這個在很多考試中可以用來解題。但是在實際的使用中,NEXT數組究竟發揮著什么樣的作用,如何用代碼實現KMP算法呢?
KMP算法是用來確定一個串是否能在另一個串中找到與之完全匹配的子串,那么首先來看一個字符串匹配的實際例子;
被匹配的字符串:
| a | b | c | d | a | b | e | f |
要匹配的字符串:
| a | b | c | d | a | b | w |
下面開始進行匹配:(i代表被匹配的字符串的當前字符下標;j代表要匹配的字符串的當前字符下標。)
| 0 | 1 | 2 | 3 | 4 | 5 | i | ? |
| a | b | c | d | a | b | e | f |
| a | b | c | d | a | b | w | ? |
| 0 | 1 | 2 | 3 | 4 | 5 | j | ? |
可以看到,在{e,w}的位置匹配失敗了,如果使用暴力的方法做,那么下一次的匹配就變成了這個樣子:
| 0 | i | 2 | 3 | 4 | 5 | 6 | 7 |
| a | b | c | d | a | b | e | f |
| ? | a | b | c | d | a | b | w |
| ? | j | 1 | 2 | 3 | 4 | 5 | 6 |
這時候 i = i-j+1;j=0;這就是暴力算法的思想:一旦匹配失敗,就讓要匹配的字符串從頭開始與被匹配的字符串進行匹配。
我們來觀察第一次匹配失敗后的情況:
| 0 | 1 | 2 | 3 | 4 | 5 | i | ? |
| a | b | c | d | a | b | e | f |
| a | b | c | d | a | b | w | ? |
| 0 | 1 | 2 | 3 | 4 | 5 | j | ? |
在要匹配的字符串的{w}位置,往前看,看到?的a,b與實心?的a,b就是我們要求的最長的相同前綴與后綴字符串
其實它們代表的實際意義是這樣的:
在{e,w}位置無法進行匹配了,但是在w之前的要匹配的字符串的所有字符都與在e之前的被匹配的字符串的所有字符完全匹配了;(這是個前提標記為@1)
下面具體分析實際情況:
| a | b | c | d | a | b | e | f |
| a | b | c | d | a | b | w | ? |
在{e,w}位置匹配失敗了,我們不想使用暴力方法;想省力,那該怎么辦呢?
要匹配的串中的w和被匹配串的e不匹配,進行下次匹配的時候,必然會有要匹配串中的w之前的某個字符取代w。也就是要將要匹配的串向右平移一個量(j+這個量<=i)。這里我們列出所有的平移情況:
(1)
| a | b | c | d | a | b | e | f | ? | ? | ? | ? | ? | ? | ? | ? |
| ? | a | b | c | d | a | b | w | ? | ? | ? | ? | ? | ? | ? | ? |
(2)
| a | b | c | d | a | b | e | f | ? | ? | ? | ? | ? | ? | ? | ? |
| ? | ? | a | b | c | d | a | b | w | ? | ? | ? | ? | ? | ? | ? |
(3)
| a | b | c | d | a | b | e | f | ? | ? | ? | ? | ? | ? | ? | ? |
| ? | ? | ? | a | b | c | d | a | b | w | ? | ? | ? | ? | ? | ? |
(4)
| a | b | c | d | a | b | e | f | ? | ? | ? | ? | ? | ? | ? | ? |
| ? | ? | ? | ? | a | b | c | d | a | b | w | ? | ? | ? | ? | ? |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(5)
| a | b | c | d | a | b | e | f | ? | ? | ? | ? | ?? | ? ? | ?? | ? |
| ? | ? | ? | ? | ? | a | b | c | d | a | b | w | ? | ? | ? | ? |
(6)
| a | b | c | d | a | b | e | f | ? | ? | ? | ? | ? | ? | ? | ? |
| ? | ? | ? | ? | ? | ? | a | b | c | d | a | b | w | ? | ? | ? |
上面就是所有的平移情況,情況(1),(2),(3)從第一個就不匹配;情況(4)從第三個不匹配;(5),(6)不需要討論;可以看到,在(4)之前都是從第一個字符起兩個串就不匹配,直到(4)才出現不是在第一個字符就不匹配的情況。然后再看(4)中的匹配上的字符串,居然是 a,b,是要匹配的 最長的相同前綴與后綴字符串。為什么會這樣,這就用到了上面的前提@1 。
再回到最初不匹配的情形下:
| a | b | c | d | a | b | e | f |
| a | b | c | d | a | b | w | ? |
正如前提@1所說,e,w之前兩個字符串完全匹配,也就是完全相同。所以要求被匹配串e之前與要匹配串從0開始相同的最長子串串也就變成了在要匹配字串中求w之前與要匹配串中從0開始相同的最長子串
| a | b | c | d | a | b | e | f |
| a | b | c | d | a | b | w | ? |
然后(1)->(2)->(3)->(4)的平移過程,其實就是使用暴力法的過程;KMP算法就是利用了這個特性,在某個位置發生不匹配的情況后,直接將比較情況變成(4)跳過了(1)、(2)、(3)這些從一開始就不匹配的匹配情況,而且斷定了在a,b已經匹配,只需要測試a,b之后的字符是否匹配就可以了,如下圖所示:
| 0 | 1 | 2 | 3 | 4 | 5 | i | 7 | ? | ? | ? | ? | ? | ? | ? | ? |
| a | b | c | d | a | b | e | f | ? | ? | ? | ? | ? | ? | ? | ? |
| ? | ? | ? | ? | a | b | c | d | a | b | w | ? | ? | ? | ? | ? |
| ? | ? | ? | ? | 0 | 1 | j | 3 | ? | ? | ? | ? | ? | ? | ? | ? |
在i的位置發生了不匹配,直接平移到了上圖中的情況,然后直接從j=2位置的要匹配字符串的字符與i=6位置的被匹配字符串的字符進行對比就可以了;
為什么能跳過暴力算法的從開始就不匹配的步驟,并且確定了這次比較中已經匹配的字符串的長度呢?
個人理解:在i位置發生了不匹配的情況,我們從i往前逐漸加大長度來取得字符串,然后確定這個字符串在要匹配的串中從0開始能否得到,知道走到得不到的時候,
也就是恰好如上圖中的 a,b,c中的c與 d,a,b中的b不想同的時候,由于d的出現,就可以確定它們從一開始就無法匹配;而反之取到 a,b的時候,說明a,b是可以匹配的,只需要確定i以及i之后與a,b之后是否能夠匹配就可以了。
最后確定一下j與NEXT數組的關系,求出要匹配的字符串的NEXT數組的值,如下:
| a | b | c | d | a | b | w |
| 0 | 1 | 1 | 1 | 1 | 2 | 3 |
在這里,j=NEXT值-1; 其中當NEXT為0的時候,j=-1;這種情況說明第一個字符就不匹配,在算法中i會直接+1,然后j也直接+1;也就是從被匹配串的第i+1位置和要匹配串從0開始進行匹配。
下面是算法的具體實現,(最近在學python,所以就用python寫了;PS:求next數組不是最優化的算法)
總結
以上是生活随笔為你收集整理的KMP算法中NEXT数组的作用以及代码实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十六进制转八进制(java)
- 下一篇: 在VC++中访问和修改系统注册表