KMP算法

来源:互联网 发布:ios Linux 编辑:程序博客网 时间:2024/05/17 02:15
  • 由于时间问题,博客写的很烂,请大家见谅。。。

  • MP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法。但是相较于其他模式匹配算法,该算法晦涩难懂,第一次接触该算法的读者往往会看得一头雾水,主要原因是KMP算法在构造跳转表next过程中进行了多个层面的优化和抽象,使得KMP算法进行模式匹配的原理显得不那么直白。本文希望能够深入KMP算法,将该算法的各个细节彻底讲透,扫除读者对该算法的困扰。

     ![next数组的计算公式](http://img.blog.csdn.net/20160428101435874) 
package com.stringCompare;import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.io.IOException;/** * 字符串匹配 * KMP算法 * 平均情况O(m+n) * 时间:2016、4、27 * @author Administrator * */public class KMP {    public static String txtToString(String path) throws IOException{//将文本文件转化为字符串        BufferedReader br=new BufferedReader(new FileReader(new File(path)));        String string="";        String str;        while ((str=br.readLine())!=null) {            str=str.replaceAll("[\\pP‘’“”,.!,。!;《》*#$&^%()-+;\r\n:]", "");//除去文本中的符号。只是为了尝试一下,其实可以不用            string+=str;        }           return string;    }     /**      * 获得字符串的next函数值      *       * @param t      *            字符串      * @return next函数值      */      public static int[] next(String t) {          int[] next = new int[t.length()];          next[0] = -1;  //索引从0开始        int i = 0;          int j = -1;          while (i < t.length()-1) {              if (j ==-1 || t.charAt(i) ==t.charAt(j)) {                  i++;                  j++;                 next[i] = j;              } else {                  j = next[j];              }          }          return next;      }    /**   * 根据字符串求next_val数组   *    * @param t   * @return   */    public static int[] next_val(String t) {          int[] next_val = new int[t.length()];          next_val[0] = -1;          int i = 0;          int j = -1;          while (i < t.length()-1) {              if (j ==-1 || t.charAt(i) ==t.charAt(j)) {                  i++;                  j++;                  if (t.charAt(i)!=t.charAt(j)) {                    next_val[i]=j;                }else {                    next_val[i]=next_val[j];                }            } else {                  j = next_val[j];              }          }          return next_val;      }      /**     * 根据字符串和next数组求  nextval数组     * @param t     * @param next     * @return     */    public static int[] nextval(String t,int[] next) {          int[] next_val = new int[t.length()];          next_val[0] = -1;          for (int j = 1; j < next_val.length; j++) {            if (t.charAt(j)!=t.charAt(next[j])) {                next_val[j]=next[j];            }else {                next_val[j]=next_val[next[j]];            }        }        return next_val;      }      /**      * KMP匹配字符串      *       * @param s      *            主串      * @param t      *            模式串      * @return 若匹配成功,返回下标,否则返回-1      */      public static int KMP_Index(String s, String t,int[] next,int pos) {          int i = pos;          int j = 0;          while (i < s.length()  && j < t.length() ) {              if (j == -1 || s.charAt(i) == t.charAt(j)) {                  i++;                  j++;              } else {                  j = next[j];              }          }          if (j > t.length()-1) {  //注意结束条件和返回值            return i - t.length();          } else              return -1; // 没有找到,返回-1      }      /**进行测试     * @param args     * @throws IOException      */    public static void main(String[] args) throws IOException {        String str1=txtToString("e:\\1.txt");        String str2=txtToString("e:\\2.txt");        int[] next=next(str2);//      int[] next_val=next_val(str2);        int[] next_val=nextval(str2,next);        long startTime=System.currentTimeMillis();   //获取开始时间        int index=KMP_Index(str1, str2,next,0);        long endTime=System.currentTimeMillis(); //获取结束时间        System.out.println(index);        System.out.println("程序运行时间: "+(endTime-startTime)+"s");    }}

1、导致KMP算法变慢的原因:
KMP的优点是避免重复匹配的记忆功能,缺点是启动慢构造next,这就导致如果要被匹配的主字符串太短(少于1k个字符都算短的)。
而朴素算法启动不需要时间。

2、KMP的优点
处理相似字符串匹配,相似度越高,字符串越长,匹配效果越好。

1 0