資料結構——串—串的模式匹配演算法
阿新 • • 發佈:2019-02-06
要找到模式串在主串中的位置,最簡單的方法就是一位一位的排查,如果相同,則比較下一項是否相同,一旦出現不同的字元,將剛剛匹配模式串主串的第一位向後移動一位繼續比較,這樣的演算法在某些串中可能會出現多次回溯,所以針對模式串的特點出現了一種改進——演算法KMP演算法
下面給出其程式碼實現:
import java.util.Scanner; /* j=0只能在上一次迴圈中j=1且字元不符合時產生,說明模式串和主串第一位不符,此時應將i、j加1,主串從下一位開始,因為j加1後是1,模式串還是從第一位開始 所以把next[1]設為0,保證了保證了過程與字元符合的情況相同,減少了一種情況 當字元相等時,i、j加1; 當字元不符合時,j賦予next[j],表示了模式串的j位與主串i位不符合時,從模式串的next[j]重新開始比較,主串位置不變 */ public class KMPIndex { int getIndex(String s,String t,int pos,int[] next)//在主串s的pos個字元之後查詢模式串t的位置(第一個字元)pos在1到s.length()-t.length()之間 { char ss[]=s.toCharArray();//先將字串轉化為陣列,便於對下標進行操作 char tt[]=t.toCharArray(); int i=pos-1; int j=1;// while(i<s.length()&&j<=t.length()) { if(j==0||ss[i]==tt[j-1])//j==0表示兩個串字元符合,都往後移動一位 { i++; j++; } else j=next[j];//如果不符合,回到指定位置重新開始匹配 } if(j==t.length()+1) return i-t.length()+1; else return -1; } /* 首先將next[1]等於0,i=1指向模式串第1位,與模式串j=0開始比較, 如果j是0; 對於第一次迴圈,i、j均加1,將next[2]指向第一位; 如果不是第一次迴圈,只能在上一次迴圈中j=1且字元不符合時產生,說明i對應字元與模式串第一位字元不相同, 此時應將i、j加1,next[i]=j;因為j加1後是1,表示一位的next指向第一位,表示下一位不符合時,直接從頭開始比較,中間不存在可能的序列 相等時,將i、j加1,next[i]=j;表示下一位的next指向模式串的第j位,表示可以直接從第j位開始比較; */ int[] getNext(String s)//模式串的next函式 { int[] next=new int[s.length()+1]; char sss[]=s.toCharArray(); char[] ss=new char[s.length()+1]; for(int i=1;i<s.length()+1;i++)//ss陣列從1開始儲存 ss[i]=sss[i-1]; int i=1; int j=0; next[1]=0; while(i<s.length()) { if(j==0||ss[i]==ss[j])//若j是0,表示需要重新匹配 { i++; j++; next[i]=j;//把下一位的next定為下一個與之比較的項 } else j=next[j]; } return next; } public static void main(String[] args) { int index,pos; KMPIndex exp; exp=new KMPIndex(); String s=new String(); String t=new String(); Scanner scan=new Scanner(System.in); System.out.print("請輸入主串:"); s=scan.nextLine(); System.out.print("請輸入模式串:"); t=scan.nextLine(); System.out.print("請輸入起始位置:"); pos=scan.nextInt(); int next[]=new int[t.length()]; next=exp.getNext(t); index=exp.getIndex(s, t, pos, next); if(index!=-1) System.out.print("已找到匹配子串,位置為"+index); else System.out.print("未找到匹配子串"); } }