經典KMP算法C++與Java實現代碼


前言:

  KMP算法是一種字符串匹配算法,由Knuth,Morris和Pratt同時發現(簡稱KMP算法)。KMP算法的關鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數以達到快速匹配的目的。比較流行的做法是實現一個next()函數,函數本身包含了模式串的局部匹配信息。由於next函數理解起來不太容易,本文同樣是基於空間換時間的做法,但將采用另一種代碼實現,希望可以更方便讀者理解!

測試數據

aseeesatba   esat
as330kdwejjl_8   jjl_
faw4etoesting tio
aabacb abac

測試結果

4
9
-1
0

(注:若匹配則返回text子串的起始index;否則返回-1)

1.暴力查找的實現一

 1 // 暴力子串查找一式:O(M*N)
 2     private static int search0(String text, String pat) {
 3         int i, j, N = text.length(), M = pat.length();
 4         for (i = 0; i <= N - M; i++) {
 5             for (j = 0; j < M; j++) {
 6                 if (text.charAt(i + j) != pat.charAt(j))
 7                     break;
 8             }
 9             if (M == j)
10                 return i;
11         }
12         return -1;
13     }

     函數傳入文本text和模式串pat,其中i和i+j分別標記text子串的首尾。若text存在子串匹配pat,則返回text子串起始index;否則返回-1;時間復雜度:O(M*N)

2.暴力查找實現二

 1 // 暴力子串查找二式:O(M*N)
 2     public static int search(String text, String pat) {
 3         int i, j;
 4         int N = text.length(), M = pat.length();
 5         for (i = 0, j = 0; i < N && j < M; i++) {
 6             if (text.charAt(i) == pat.charAt(j))
 7                 j++;
 8             else {
 9                 i -= j;
10                 j = 0;
11             }
12         }
13         return (j == M) ? (i - M) : -1;
14     }

    同樣的一種暴力查找算法,通過不斷的回溯文本串中的“i”進行判斷。若text存在子串匹配pat,則返回text子串起始index;否則返回-1;時間復雜度:O(M*N)

3.KMP算法(空間換時間)

    為了優化算法時間復雜度,我們嘗試進行一些信息存儲,引入了額外的空間存儲 dfa[][]。

    從上述第二種暴力查找算法中,我們可以得到啟發。即,通過記錄“j”保證“i”只能往右移動,無需往左回退。其中,dfa[i][j]

表示文本串中當前字符‘charAt(i)’時,下個文本字符'charAt(i+1)'應該與模式串匹配的位置(0~j)。

    這里我們引入有窮自動機DFA對dfa[][]進行數值的初始化。以模式串“aabacb”為例,匹配pat的DFA狀態圖如下:

    對應的代碼如下:

1         //構造dfa[][]
2         dfa[pat.charAt(0)][0] = 1;
3         for(int X=0,j=0;j<M;j++){
4             for(int c=0;c<R;c++){
5                 dfa[c][j] = dfa[c][X];
6             }
7             dfa[pat.charAt(j)][j] = j+1;
8             X = dfa[pat.charAt(j)][X];
9         }

    其中,“X”表示不同的dfa狀態,上述代碼構造dfa[][]的時間復雜度為:O(N*R);

------------------------------------------------

Java完整代碼

 1 package ch05.string.substring;
 2 
 3 import java.io.File;
 4 import java.util.Scanner;
 5 
 6 public class KMP {
 7     
 8     private int R = 255;
 9     private String pat;
10     private int[][] dfa;
11     
12     public KMP(String pat) {
13         this.pat = pat;
14         int M = pat.length();
15         dfa = new int[R][M];
16         
17         //構造dfa[][]
18         dfa[pat.charAt(0)][0] = 1;
19         for(int X=0,j=0;j<M;j++){
20             for(int c=0;c<R;c++){
21                 dfa[c][j] = dfa[c][X];
22             }
23             dfa[pat.charAt(j)][j] = j+1;
24             X = dfa[pat.charAt(j)][X];
25         }
26         
27     }
28     
29     public int search(String text){
30         int i,j;
31         int N = text.length(),M = pat.length();
32         for(i=0,j=0;i<N && j<M; i++){
33             j = dfa[text.charAt(i)][j];
34         }
35         return j==M?(i-M):-1;
36     }
37     
38     public static void main(String[] args) throws Exception {
39         //從文件讀入數據
40         Scanner input = new Scanner(new File("datain.txt"));
41         while(input.hasNext()){
42             String text = input.next();
43             KMP kmp = new KMP(input.next());
44             int ans = kmp.search(text);
45             //輸出答案
46             System.out.println(ans);
47         }
48     }
49 }

------------------------------------------------

C/C++完整代碼  

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<string>
 5 using namespace std;
 6 const int maxn=1e4+10;
 7 const int R=256;
 8 int dfa[R][maxn];
 9 
10 string text,pat;
11 void init(){
12     int M=pat.length();
13     dfa[pat[0]][0] = 1;
14     for(int X=0,j=1;j<M;j++){
15         /**直接從dfa[][X]復制到dfa[][j]*/
16         for(int c=0;c<R;c++){
17             dfa[c][j] = dfa[c][X];
18         }
19         /**匹配到,繼續往右走*/
20         dfa[pat[j]][j] = j+1;
21         X = dfa[pat[j]][X];
22     }
23 
24 }
25 int search1(){
26     init();
27     int i,j,N = text.length(),M = pat.length();
28     for(i=0,j=0;i<N && j<M;i++){
29         j = dfa[text[i]][j];
30     }
31     return j==M?(i-M):-1;
32 }
33 int main(){
34     freopen("datain.txt","r",stdin);
35     while(cin>>text>>pat){
36         cout<<search1()<<endl;
37     }
38     return 0;
39 }

Reference:

  【1】Algorithms(4th) -謝路雲

      【2】http://baike.baidu.com/link?url=_WLufLz1lw2e4eMgU6DI8IblUkp838Qf595Nqxfg2JN3aqNED2FFe3U6J9yPmUv_zKfFqAAQJid7Gzho3ork8K


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM