比BF算法改进的地方在:每一趟匹配出现字符不等时,不需回溯指针i,而是利用已经得到的“部分匹配”的结果,将模式T向右滑尽可能远后,继续进行比较。
需要计算next函数值:
- next[0]=-1, next[1]=0。
- 在求解next[j]时,令k=next[j-1],
-
比较T[j-1]与T[k]的值,
a. 若T[j-1]等于T[k],则next[j]=k+1。
b. 若T[j-1]不等于T[k],令k=next[k],若k等于-1,则next[j]=0,否则跳至3。
1 import java.util.Scanner; 2 3 public class KMP { 4 public static void main(String[] args) { 5 menu(); 6 Scanner scan= new Scanner(System.in); 7 String S=scan.next(); 8 String T=scan.next(); 9 System.out.println("输入完毕,算法运行结果如下:"); 10 System.out.println("主串S:"+S+" 模式T:"+T); 11 scan.close(); 12 char[] charS=S.toCharArray(); 13 char[] charT=T.toCharArray(); 14 int pos=1; 15 int next[] = new int[charT.length+1]; 16 int nextval[] = new int[charT.length+1]; 17 getNext(charT,next); 18 getNextval(charT,nextval); 19 run(charS,charT,pos,nextval); 20 } 21 public static void menu() { 22 System.out.println("串的模式匹配算法——KMP算法\n"); 23 System.out.println("请在以下分别输入主串S,和需要匹配的模式T:"); 24 } 25 public static void getNextval(char[] charT,int nextval[]) { 26 int i=1; 27 int j=0; 28 nextval[0]=-1; 29 nextval[1]=0; 30 while(i<charT.length) 31 { 32 if(j==0 || charT[i-1]==charT[j-1]) 33 { 34 ++i; 35 ++j; 36 if(charT[i-1]!=charT[j-1]) { 37 nextval[i]=j; 38 }else { 39 nextval[i]=nextval[j]; 40 } 41 }else 42 { 43 j=nextval[j]; 44 } 45 } 46 System.out.print("next函数修正值为:"); 47 for (i=1;i< charT.length+1; i++) { 48 System.out.print(nextval[i]+" "); 49 } 50 System.out.print("\n"); 51 } 52 public static void getNext(char[] charT,int next[]) { 53 int i=1; 54 int j=0; 55 next[0]=-1; 56 next[1]=0; 57 while(i<charT.length) 58 { 59 if(j==0 || charT[i-1]==charT[j-1]) 60 { 61 ++i; 62 ++j; 63 next[i]=j; 64 }else 65 { 66 j=next[j]; 67 } 68 } 69 System.out.print("next函数值为:"); 70 for (i=1;i< charT.length+1; i++) { 71 System.out.print(next[i]+" "); 72 } 73 System.out.print("\n"); 74 } 75 public static void run(char[] charS,char[] charT,int pos,int nextval[]) { 76 int i=pos; 77 int j=1; 78 while(i<=charS.length && j<=charT.length) 79 { 80 if(j==0 || charS[i-1] == charT[j-1]) 81 { 82 ++i; 83 ++j; 84 }else 85 { 86 j=nextval[j]; 87 } 88 } 89 if(j>charT.length) 90 { 91 System.out.println("匹配成功,序号为"+(i-charT.length)); 92 }else 93 { 94 System.out.println("匹配失败"); 95 } 96 System.out.println("——程序运行完毕,检测新的模式请重新运行程序——"); 97 } 98 }
KMP算法仅当模式与主串之间存在许多“部分匹配”的情况下,才显得逼BF算法快得多,但是对处理外设输入的庞大文件很有效,可以边读入边匹配,无需回头重读。