KMP算法的Java实现(优化和非优化求next数组)

最近学习在字符串匹配时,会用到KMP算法,比BF(暴力)算法性能提高了许多,于是用Java实现了一下。

算法中主要问题就是求得next数组,在这里也出现了可以优化的地方,算法原理讲解很多博客也给出,代码供上。。。

写的不好,请指出问题。


package algorithm;

public class KMR {

	
	/**
	 * 记m=match.length()
	 * 此算法为未改进的KMP算法中的求next数组
	 * next[j]表示array[0]~array[j-1]中真前缀和真后缀相等的最大长度,记为k
	 * 在求next[j]时,对array[0]~array[j-1]进行了j-1躺搜索
	 * 算法复杂度为O(m^3)
	 * */
	public static int[] getNext(String match) {

		int[] next=new int[match.length()];
		next[0]=-1;
		int i,j,len;
		for(j=1;j<match.length();j++)   // 相等子串的从match[0]-match[j-1]查找
		{
			for( len=j-1;len>=1;len--)
			{
				for( i=0;i<len;i++)		// 依次比较match[0]-match[len-1] 与 match[j-len]-match[j-1]
				{
					if(match.charAt(i)!=match.charAt(i+j-len)) 
						break;
				}
				if(len==i)
				{
					next[j]=len;
					break;
				}
			}
			if(len<1)
				next[j]=0;
		}
		System.out.print(match+"的next[]数组为:");
		for(int interger:next)
			System.out.print(interger+" ");
		
		return next;
	}
	
	/*
	 * 此算法为改进过的KMP算法中的求next数组
	 * next[j]表示array[0]~array[j-1]中真前缀和真后缀相等的最大长度,记为k
	 * 我们会发现 
	 * if(array[j]==array[k]),那么next[j]自然等于k+1,相当于原来的前缀和后缀都添加上了相同的一个字符
	 * if(array[j]==array[k]), 那么我们需要去求array[0]~array[j-1]中真前缀和真后缀相等的第二长的长度
	 * 记为k'=next[k] 再判断if(array[j]==array[k'])  
	 * 一直做同样的操作,直到array[j]==array[k'''']或*next[k''''']=-1停止
	 * 算法复杂度为O(m)*/
	public static int[] advancedGetNext(String match)
	{
		
		int[] next=new int[match.length()];
		next[0]=-1;  // 初值,每个字符串的第一个字符一定不存在最大前缀和最大后缀
		int j=1;
		int k=-1;
		while(j<match.length())
		{
			
			if(k==-1)
			{
				next[j]=0;
				j++;
				k=next[j-1];  // 提前算好下一次迭代时的k
			}
			else if(match.charAt(j-1)==match.charAt(k)) {
				next[j]=k+1;
				j++;
				k=next[j-1];
			}
			else {
					k=next[k];
			}
		}
		System.out.print(match+"的next[]数组为:");
		for(int interger:next)
			System.out.print(interger+" ");
		return next;
		
	}
	
	
	public static int KMP(String str,String match) {
		int[] next=advancedGetNext(match);
//		int[] next=getNext(match);
		int i=0,j=0;
		while(i<str.length()&&j<match.length())
		{
			if(str.charAt(i)==match.charAt(j))
			{
				i++;
				j++;
			}
			else {
				j=next[j];
				if(j==-1)   // 子串的最大前缀和最大后缀不存在
				{
					i++;
					j++;  // 这条语句也可以写成j=0;
				}
			}
		}
		if(j==match.length())
		{
			return i-match.length();
		}
		else {
			return -1;
		}
		
	}
	
	
	public static void main(String[] args) {
		String str="ababaababcb";
		String match1="ababc";
		String match2="abcd";
		int index1=KMP(str,match1);
		System.out.println("\n"+match1+"在"+str+"中的起始索引号为:"+index1);
		int index2=KMP(str,match2);
		System.out.println("\n"+match2+"在"+str+"中的起始索引号为:"+index2);
	}
	
	
	
	
	
}

猜你喜欢

转载自blog.csdn.net/qq_37174526/article/details/79592256
今日推荐