KMP算法的Java实现(优化和非优化求next数组)
2018-03-17 15:11
281 查看
最近学习在字符串匹配时,会用到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);
}
}
算法中主要问题就是求得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);
}
}
相关文章推荐
- KMP算法之最终实现及 NEXT数组的优化
- KMP算法中next数组的理解与算法的实现(java语言)
- KMP模式匹配算法原理分析、next数组优化及java实现
- KMP算法理解与next数组的实现
- KMP算法与next数组的代码初步实现
- 字符串匹配问题——求给定字符串的next数组以及KMP算法实现
- KMP算法next数组计算方法的优化
- KMP算法的next、next value数组代码实现及POJ3461
- 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案
- KMP算法中NEXT数组的作用以及代码实现
- KMP_next数组_while详解_Java实现
- KMP算法java版,next数组求法简单易懂
- 小实例-实现对成绩总分由高到低的排序-Java中数组对象的排序
- JAVA里实现一个数组全排列的方法
- 第2章 Java编程基础——FAQ2.27 数组的排序算法有哪些?如何实现?
- 实现AMF3与Java之间数组的传递(动态创建数组)...
- 第2章 Java编程基础——FAQ2.26 如何实现数组的复制?
- java实现数组的所有组合
- 用java数组实现基本链表和可自扩充的链表
- 数据结构复习:栈-Java数组实现