这两天随便翻了翻算法导论,无意看到了模式匹配一章节,由于在本科上数据结构时也学过一点,但是记得老师那时说模式匹配也不做硬性要求(要链表,栈,队列)不会考试,考研也不会考,所以就没有花很多时间看相应的算法;现在看到了这了,有点兴趣所以看了看,并用代码实现。
BF算法和KMP算法比较:
BF算法思路:字串和母串中的字符比较相等时,均后移,否则母串开始比较的位置会移至到上次开始比较的下个位置,字串则移至0位置;如此循环。时间复杂度O(n*m).
KMP算法思路:由于BF算法的缺点(每次不等时,母串均要前移,根据字串的结构可以发现其实母串前移,会做很多无用的比较),所以KMP算法采用当不等时,母串不移动,字串向右移,而具体移多少,移到什么位置,就是本算法的难点即求next[m]的值;(这个next[m]值在此就不详细说明,可以看很多牛人的博客,都介绍的很详细,或者直接看数据结构那本经典的书,上面介绍的很详细)。时间复杂度O(n+m).
package test;
import java.util.ArrayList;
//如何找到所有的位置
public class ModelMatch {
public static void main(String[] args) {
// TODO Auto-generated method stub
String T="acabaabaabcacaabc";
String S="abaabcac";
//System.out.println(T);
//for(int i=0;i<str.length();++i)
//System.out.println(str.charAt(i));
System.out.println("======采用BF算法========");
int k=index(T,S,0);
if(k!=-1)
System.out.println("\n匹配成功 k:"+k+"\n======================\n");
else
System.out.println("匹配不成功!"+"\n======================\n");
System.out.println("\n======采用KMP算法========");
int kmp=indexKMP(T,S,0);
if(kmp!=-1)
System.out.println("\n匹配成功kmp:"+kmp+"\n======================");
else
System.out.println("没有找到!"+"\n======================");
int[] a=indexAll(T,S,0); //求所有模式串的出现的位置
System.out.println("所有出现的位置:");
for(int rep:a){
System.out.println(rep);
}
}
//采用KMP算法
static int indexKMP(String T,String S,int pos){
int[] next=new int[S.length()];
int i=pos,j=0,jf=0;
boolean flag=false;
int count=1;
System.out.println("第"+count+"趟比较");
System.out.println(T);
System.out.print(S.charAt(0));
getNext(S,next);//先得到next
while(i<T.length() && j<S.length()){
if(j==-1 || T.charAt(i)==S.charAt(j)){
if(j!=-1){
jf=j+1;
jf=i+1-jf;
}
++i;++j;flag=true;
}
else{
flag=false;
j=next[j];
jf=i-j;
count++;
}
if(j<S.length()){
if(flag==true){
System.out.println("\n"+T+" 字符比较相等,均后移 "+" T中 i移至:"+i+",S中 j移至:"+j);
}
else{
System.out.println("\n"+"第"+count+"趟比较");
if(j==-1)
System.out.println(T+" 其中next["+(j+1)+"]="+j+" 所以"+" S串j移至:"+(j+1)+", T串i也后移为:"+(i+1));
else
System.out.println(T+",next["+jf+"]="+j+" 不相等,T串i位置不变为:"+i+", S串j移至:"+j);
}
for(int k=0;k<jf;k++){
System.out.print(" ");
}
for(int k=0;k<=j;k++){
System.out.print(S.charAt(k));
}
}
}
if(j>=S.length())
return i-j;
else
return -1;
}
//求next值
static void getNext(String S,int[] next){
int i=0;
int j=-1;
next[0]=-1;
while(i<S.length()-1){
if(j==-1 || S.charAt(i)==S.charAt(j)){
++i;++j;next[i]=j;
}
else j=next[j];
}
}
//
static int index(String T,String S,int pos){
int i=pos,j=0,start=0;
boolean flag=false;
int count=1;
System.out.println("第"+count+"趟比较");
System.out.println(T);
System.out.print(S.charAt(0));
while(j<S.length() && i<T.length()){
if(T.charAt(i)==S.charAt(j)){
++i;++j;flag=true;
}
else{
i=i-j+1;
start=i;//标记开始比较时i值,以便模式串可以向后移动start个空格
j=0; //顺序不能颠倒
flag=false;
count++;
}
if(j<S.length()){
if(flag==true){
System.out.println("\n"+T+" 字符比较相等,均后移"+"T中 i移至:"+i+",S中 j移至:"+j);
}
else{
System.out.println("\n"+"第"+count+"趟比较");
System.out.println(T+" 字符比较不相等,T中 i移至:"+start+",S中 j移至:"+j);
}
for(int k=0;k<start;k++){
System.out.print(" ");
}
for(int k=0;k<=j;k++){
System.out.print(S.charAt(k));
}
}
}
//System.out.println(j);
if(j>=S.length())
return i-j;
else
return -1;
}
static int[] indexAll(String T,String S,int pos){
int i=pos,j=0;
ArrayList<String> list=new ArrayList<String>();
while(i<T.length()){
if(T.charAt(i)==S.charAt(j)){
++i;++j;
}
else{
i=i-j+1;
j=0; //顺序不能颠倒
}
if(j>=S.length()){
//System.out.println(i-j);
list.add(String.valueOf(i-j));
++i;
j=0;
}
}
//System.out.println(j);
int[] a=new int[list.size()];
for(int k=0;k<list.size();k++){
a[k]=Integer.parseInt(list.get(k));
}
return a;
}
}