KMP算法学习

(1) 参考网址:

KMP算法:   http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html  

        --- 用递推思想和直接法两种方式求解next数组

KMP学习心得:   http://www.java3z.com/cwbwebhome/article/article19/res023.html?id=3737

       --- 当一个字符串以0为起始下标时,next[i]可以描述为"不为自身的最大首尾重复子串长度"。

KMP字符串模式匹配中模式函数:  http://www.java3z.com/cwbwebhome/article/article19/re022.html?id=3731

       --- 详细讲解了next数组的求解方法【next数组求解的改进版本】

 

(2) 经典总结:

一、怎么求串的模式值next[n]
定义:
(1)next[0]= –1  意义:任何串的第一个字符的模式值规定为-1。
(2)next[j]= –1   意义:模式串T中下标为j的字符,如果与首字符相同,且j的前面的1~k个字符与开头的1~k个字符不等或者相等但
              T[k]==T[j]
(1≤k<j)。 如:T=”abCabCad” 则 next[6]=-1,因T[3]=T[6]  bCa

(3)next[j]=k      意义:模式串T中下标为j的字符,如果j的前面k个字符与开头的k个字符相等,且T[j] != T[k] (1≤k<j)。
               即T[0]T[1]T[2]...T[k-1]== T[j-k]T[j-k+1]T[j-k+2]…T[j-1] 且T[j] != T[k].(1≤k<j);
(4)next[j]=0        意义:除(1)(2)(3)的其他情况

 

二、next 函数值究竟是什么含义

设在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函数值next[n],
1. next[n]= -1 表示S[m]和T[0]间接比较过了,不相等,下一次比较 S[m+1] 和T[0]
2. next[n]=0 表示比较过程中产生了不相等,下一次比较 S[m] 和T[0]。
3. next[n]= k >0 但k<n, 表示,S[m]的前k个字符与T中的开始k个字符已经间接比较相等了,下一次比较S[m]和T[k]相等吗?
4. 其他值,不可能。

(3) 代码实现 【参考书籍:《数据结构与算法 Java语言描述》 邓俊辉 著】

 

原书代码:【略有改动】

?
package dsa;
/*
  * 串模式匹配:KMP算法
  */
public class PM_KMP {
  
     public static void main(String[] args) {
         System.out.println(PM( "ababacab" , "aca" ));
     }
  
     public static int PM(String T, String P) { // KMP算法
         int [] next = BuildNextImproved(P); // 构造next[]表
         int i = 0 ; // 主串指针
         int j = 0 ; // 模式串指针
         while (j < P.length() && i < T.length()) { // 自左向右逐个比较字符
             ShowProgress(T, P, i - j, j);
             ShowNextTable(next, i - j, P.length());
             System.out.println();
             if ( 0 > j || T.charAt(i) == P.charAt(j)) { // 若匹配,或P已移出最左侧(提问:这两个条件能否交换次序?)
                 i++;
                 j++; // 则转到下一对字符
             } else
                 // 否则
                 j = next[j]; // 模式串右移(注意:主串不用回退)
         } // while
         return (i - j);
     }
  
     protected static int [] BuildNext(String P) { // 建立模式串P的next[]表
         int [] next = new int [P.length()]; // next[]表
         int j = 0 ; // “主”串指针
         int t = next[ 0 ] = - 1 ; // “模式”串指针
         while (j < P.length() - 1 )
             if ( 0 > t || P.charAt(j) == P.charAt(t)) { // 匹配
                 j++;
                 t++;
                 next[j] = t; // 此句可以改进...
             } else
                 // 失配
                 t = next[t];
         for (j = 0 ; j < P.length(); j++)
             System.out.print( "\t" + P.charAt(j));
         System.out.print( "\n" );
         ShowNextTable(next, 0 , P.length());
         return (next);
     }
  
     protected static int [] BuildNextImproved(String P) { // 建立模式串P的next[]表(改进版本)
         int [] next = new int [P.length()];
         ; // next[]表
         int j = 0 ; // “主”串指针
         int t = next[ 0 ] = - 1 ; // “模式”串指针
         while (j < P.length() - 1 )
             if ( 0 > t || P.charAt(j) == P.charAt(t)) { // 匹配
                 j++;
                 t++;
                 next[j] = (P.charAt(j) != P.charAt(t)) ? t : next[t]; // 注意此句与未改进之前的区别
             } else
                 // 失配
                 t = next[t];
         for (j = 0 ; j < P.length(); j++)
             System.out.print( "\t" + P.charAt(j));
         System.out.print( "\n" );
         ShowNextTable(next, 0 , P.length());
         return (next);
     }
  
     protected static void ShowNextTable( int [] N, int offset, int length) { // 显示next[]表,供演示分析
         int i;
         for (i = 0 ; i < offset; i++)
             System.out.print( "\t" );
         for (i = 0 ; i < length; i++)
             System.out.print( "\t" + N[i]);
         System.out.print( "\n\n" );
     }
  
     protected static void ShowProgress( // 动态显示匹配进展
             String T, // 主串
             String P, // 模式串
             int i, // 模式串相对于主串的起始位置
             int j) // 模式串的当前字符
     {
         int t;
         System.out.println( "-------------------------------------------" );
         for (t = 0 ; t < T.length(); t++)
             System.out.print( "\t" + T.charAt(t));
         System.out.print( "\n" );
         if ( 0 <= i + j) {
             for (t = 0 ; t < i + j; t++)
                 System.out.print( "\t" );
             System.out.print( "\t|" );
         }
         System.out.println();
         for (t = 0 ; t < i; t++)
             System.out.print( "\t" );
         for (t = 0 ; t < P.length(); t++)
             System.out.print( "\t" + P.charAt(t));
         System.out.print( "\n" );
         System.out.println();
     }
}

 

精简代码:

 

?
package dsa.me;
  
public class Kmp {
  
     public static void main(String[] args) {
         System.out.println(kmp( "ababa" , "bab" ));
         System.out.println(kmp( "ababa" , "bba" ));
     }
  
     // KMP算法
     public static int kmp(String T, String P) {
         int next[] = buildeNextImproved(P);
         int i = 0 ;
         int j = 0 ;
         while (i < T.length() && j < P.length()) { // 一定要限制它们在范围内,不然会报错
             if (j < 0 || T.charAt(i) == P.charAt(j)) { // 匹配,i和j都向右移动,j<0(j=-1)
                 i++;
                 j++;
             } else { // 不匹配,只要移动j,i不要回溯
                 j = next[j];
             }
         }
         if (j >= P.length())
             return (i - j);
         else
             return - 1 ;
     }
  
     // 求next数组
     public static int [] buildeNext(String P) {
         int [] next = new int [P.length()];
         int j = 0 ;
         int t = - 1 ; // 初始值是-1
         next[ 0 ] = - 1 ;
         while (j < P.length() - 1 ) {
             if (t == - 1 || P.charAt(t) == P.charAt(j)) { // 匹配---如果在j这里不存在首尾相同的字符串,那么next[j]就会等于0
                 t++;
                 j++;
                 next[j] = t; // 由这里看出while条件中j不能等于P.length()-1
             } else { // 不匹配
                 t = next[t];
             }
         }
         return next;
     }
  
     // 求next数组的改进版本
     public static int [] buildeNextImproved(String P) {
         int [] next = new int [P.length()];
         int j = 0 ;
         int t = - 1 ; // 初始值是-1
         next[ 0 ] = - 1 ;
         while (j < P.length() - 1 ) {
             if (t == - 1 || P.charAt(t) == P.charAt(j)) { // 匹配---如果在j这里不存在首尾相同的字符串,那么next[j]就会等于0
                 t++;
                 j++;
                 next[j] = (P.charAt(j) != P.charAt(t)) ? t : next[t]; // 改进的地方
             } else { // 不匹配
                 t = next[t];
             }
         }
         return next;
     }
  
}

 

附上参考书籍的对应章节pdf下载地址:http://115.com/file/dpkg6art#数据结构与算法(Java_描述).pdf

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值