通過圖片對比帶給你不一樣的KMP演算法體驗

來源:互聯網
上載者:User

標籤:第一個字元   alt   解釋   方法   體驗   函數   ptr   細節   基礎   

KMP 演算法,俗稱“看毛片”演算法,是字串匹配中的很強大的一個演算法,不過,對於初學者來說,要弄懂它確實不易。

筆者認為,KMP 演算法之所以難懂,很大一部分原因是很多實現的方法在一些細節的差異。體現在幾個方面: next 數組,有的叫做“失配函數”,其實是一個東西; next 數組中,有的是以下標為 0 開始的,有的是以 1 開始的; KMP 主演算法中,當發生失配時,取的 next 數組的值也不一樣!就這樣,各說各的,亂的很!

所以,在闡述我的理解之前,我有必要說明一下,我是用 next 數組的, next 數組是以下標 0 開始的!還有,我不會在一些基礎的概念上浪費太多,所以你在看這篇文章時必須要懂得一些基本的概念,例如 “ 樸素字串匹配 ”、“ 首碼 ” , “ 尾碼 ” 等!還有就是,這篇文章的每一個字都是我辛辛苦苦碼出來的,圖也是我自己畫的!如果要轉載,請註明出處!好了,開始吧!

假設在我們的匹配過程中出現了這一種情況:

根據 KMP 演算法,在該失配位會調用該位的 next 數組的值!在這裡有必要來說一下next 數組的作用!說的太繁瑣怕你聽不懂,讓我用一句話來說明:

返回失配位之前的最長公用前尾碼!

好,不管你懂不懂這句話,我下面的文字和圖應該會讓你懂這句話的意思以及作用的!

首先,我們取之前已經匹配的部分(即藍色的那部分!)

我們在上面說到 next 數組的作用時,說到 “ 最長公用前尾碼 ” ,體現到圖中就是這個樣子!

接下來,就是最重要的了!

沒錯,這個就是 next 數組的作用了 :

返回當前的最長公用前尾碼長度,假設為 len 。因為數組是由 0 開始的,所以 next數組讓第 len 位與主串匹配就是拿最長首碼之後的第 1 位與失配位重新匹配,避免匹配串從頭開始!如所示!

(重新匹配剛才的失配位!)

 

如果都說成這樣你都不明白,那麼你真的得重新理解什麼是 KMP 演算法了!

 

接下來最重要的,也是 KMP 演算法的核心所在,就是 next 數組的求解!不過,在這裡我找到了一個全新的理解方法!如果你懂的上面我寫的的,那麼下面的內容你只需稍微思考一下就行了!

 

跟剛才一樣,我用一句話來闡述一下 next 數組的求解方法,其實也就是兩個字:

繼承

a 、當前面字元的前一個字元的對稱程度為 0 的時候,只要將當前字元與子串第一個字元進行比較。這個很好理解啊,前面都是 0 ,說明都不對稱了,如果多加了一個字元,要對稱的話最多是當前的和第一個對稱。比如 agcta 這個裡面 t 的是 0 ,那麼後面的 a 的對稱程度只需要看它是不是等於第一個字元 a 了。

b 、按照這個推理,我們就可以總結一個規律,不僅前面是 0 呀,如果前面一個字元的 next 值是 1 ,那麼我們就把當前字元與子串第二個字元進行比較,因為前面的是1 ,說明前面的字元已經和第一個相等了,如果這個又與第二個相等了,說明對稱程度就是 2 了。有兩個字元對稱了。比如上面 agctag ,倒數第二個 a 的 next 是 1 ,說明它和第一個 a 對稱了,接著我們就把最後一個 g 與第二個 g 比較,又相等,自然對稱成都就累加了,就是 2 了。  

c 、按照上面的推理,如果一直相等,就一直累加,可以一直推啊,推到這裡應該一點難度都沒有吧,如果你覺得有難度說明我寫的太失敗了。

當然不可能會那麼順利讓我們一直對稱下去,如果遇到下一個不相等了,那麼說明不能繼承前面的對稱性了,這種情況只能說明沒有那麼多對稱了,但是不能說明一點對稱性都沒有,所以遇到這種情況就要重新來考慮,這個也是痛點所在。

如果藍色的部分相同,則當前 next 數組的值為上一個 next 的值加一,如果不相同,就是我們下面要說的!

如果不相同,用一句話來說,就是:

從前面來找子前尾碼

1 、如果要存在對稱性,那麼對稱程度肯定比前面這個的對稱程度小,所以要找個更小的對稱,這個不用解釋了吧,如果大那麼就繼承前面的對稱性了。

2 、要找更小的對稱,必然在對稱內部還存在子對稱,而且這個必須緊接著在子對稱之後。

 

如果不能理解,那麼看一吧!

好了,我已經把該說的儘可能以最淺顯的話和最直接的圖展示出來了,如果還是不懂,那我真的沒有辦法了!

說了這麼多,下面是代碼實現

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define N 100 5  6 void cal_next( char * str, int * next, int len ) 7 { 8     int i, j; 9 10     next[0] = -1;11     for( i = 1; i < len; i++ )12     {13         j = next[ i - 1 ];14         while( str[ j + 1 ] != str[ i ] && ( j >= 0 ) )15         {16             j = next[ j ];17         }18         if( str[ i ] == str[ j + 1 ] )19         {20             next[ i ] = j + 1;21         }22         else23         {24             next[ i ] = -1;25         }26     }27 }28 29 int KMP( char * str, int slen, char * ptr, int plen, int * next )30 {31     int s_i = 0, p_i = 0;32 33     while( s_i < slen && p_i < plen )34     {35         if( str[ s_i ] == ptr[ p_i ] )36         {37             s_i++;38             p_i++;39         }40         else41         {42             if( p_i == 0 )43             {44                 s_i++;45             }46             else47             {48                 p_i = next[ p_i - 1 ] + 1;49             }50         }51     }52     return ( p_i == plen ) ? ( s_i - plen ) : -1;53 }54 55 int main()56 {57     char str[ N ] = {0};58     char ptr[ N ] = {0};59     int slen, plen;60     int next[ N ];61 62     while( scanf( "%s%s", str, ptr ) )63     {64         slen = strlen( str );65         plen = strlen( ptr );66         cal_next( ptr, next, plen );67         printf( "%d\n", KMP( str, slen, ptr, plen, next ) );68     }69     return 0;70 }

 

通過圖片對比帶給你不一樣的KMP演算法體驗

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.