`
ikon
  • 浏览: 107156 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

模式匹配算法详解:KMP算法 .

    博客分类:
  • j2se
阅读更多

基本的模式匹配算法

假设现在有主串S=s1,...,sn,,模式串P=p1,...,pm,基本的模式匹配算法是将P中的字符p1与S中的字符s1比较,如果相等,则依次递增比较pi+1和sj+1。如果不相等,则将p1与S中的字符s2比较,依次类推。如果存i=m,则存在匹配模式,否则匹配失败。

 

KMP算法

KMP算法是由由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,所以人们称它为克努特—莫里斯—普拉特算法,该算法的时间复杂度为O(n+m),n为主串的长度,m为模式串的长度。

KMP算法的特点是不需要回潮对主串的匹配,核心思想是如果模式串当前字符a与主串当前的字符b不匹配,分两种情况,如果对于模式串中字符c之前的一个子串s,存在一个以模式串首位开始与子串s相同的子串s',则对于之前子串s其实已经通过其之后子串s'完成匹配了,所以不再需要比较,则从模式串的中间位置开始比较。如果不存在这样的子串s',则说明字符b之前开始的子串都不与模式串匹配。

算法思路:该算法的关键是当不匹配时,下一次比较将模式串的第几位开始。根据前面的分析,该位置与模式串相关,由于和主串的比较还是依次从头至尾 的,模式串重新比较的位置与主串无关,这就意味着模式串不变时,模式串中下一个匹配的位置是确定的,而不受主串影响。

对于模式串P=p1,...,pi-1,pi,...,pm如果模式串的子串p1,...,pi-1,已经和主串S=s1,...,sn中子串sj,...,sj+i-1匹配成功,而pi与sj+i不相等,即不匹配,则我们要使得j=j+1,即将模式串与主串中当前位置的下一个位置的字符串起开始比较。正如前文所说的,我们不是重新从模式串的首位开始比较,而跳跃地从一个中间位置开始比较。我们用一个长度为m的数组next[m]保存模式串中当每一个位置的字符匹配失败后,下一次模式串重新开始比较的位置。

next的值事实上是针对当模式串P中第j位的字符P[j]与主串匹配失败时计算的,分为三种情况:

第一种,next[i] = -1,当i=0时;

第二种next[i] = max{k|1<k<i且p[0],...,p[k-1]=[i-k],...p[i-1]};

其他情况,next[i] = 0

这该算法的JAVA源码如下:

 

  1. /** 
  2.  *  
  3.  * @author newstar 
  4.  * @since 2011-09-27 
  5.  * 
  6.  */  
  7. public class KMP1 {  
  8.   
  9.       
  10.     public int match(String p,String t){  
  11.         String pattern = p;  
  12.         String text = t;  
  13.         int i = 0, j = 0;  
  14.         int[] next = calculate_next(pattern);  
  15.         while(i < pattern.length()&& j <text.length()){  
  16.             if(i==-1|| pattern.charAt(i)==text.charAt(j)){  
  17.                 ++i;  
  18.                 ++j;  
  19.             }  
  20.             else{  
  21.                 i = next[i];  
  22.             }  
  23.         }  
  24.         if(j > pattern.length())   
  25.             return j-pattern.length();  
  26.         else return 0;  
  27.     }  
  28.       
  29.     public int[] calculate_next(String pattern){  
  30.         int m = pattern.length();  
  31.         System.out.println(m);  
  32.         int[] next = new int[m];  
  33.         int i = 0,j = -1;  
  34.         next[0] = -1;  
  35.         while(i<m-1){  
  36.             if(j==-1||pattern.charAt(i)==pattern.charAt(j)){  
  37.                 ++i;  
  38.                 ++j;  
  39.                 next[i] = j;  
  40.             }  
  41.             else{  
  42.                 j = next[j];  
  43.             }  
  44.         }  
  45.         return next;  
  46.     }  
  47.   
  48.     /** 
  49.      * @param args 
  50.      */  
  51.     public static void main(String[] args) {  
  52.         // TODO Auto-generated method stub   
  53.         String pattern = "abcfdabceg";  
  54.         String text = "egaradfaababcfdabcegeabcbcae";  
  55.         KMP1 run = new KMP1();  
  56.         int position = run.match(pattern,text);  
  57.         System.out.println(position);  
  58.   
  59.     }  
  60. }  

 

 

细心的读者也许会发现calculate_next函数和match函数十分类似,其实对于next的计算其实已经将模式串即当作主串又当作模式串来计算的。因为KMP算法本质其实是考虑到模式串中有相同子串,前面的子串和后面的子串相同,如果后面的子串已经是匹配成功的时,前面的子串必定和相应的主串是相匹配的。

仔细分析以下发现其实next值的计算还有改时,可以减少对主串的比较,改进后的next值的计算,分为三种情况:

第一种,如果这p[i]=p[0],则next[i]=-1。表明模式串的当前位置与模式串的首位相同,当模式串当前位置与主串的当前位匹配失败时,则模式串的首位与主串的当前位也会匹配失败,则模式串的首位应和主串当前位的下一位比较,即主串当前位向右移一位。模式串当前位为首位。

第二种,如果第一种情况不满足时,当p[0],...,p[k-]=p[i-k],...p[i],k>=0,则next[i] = 0。表明如果模式串当前位置为结束位的一个子串与模式串的首位开始的一个子串相等,如果模式串当前位置匹配失败,则表明模式串首位开始的那个子串也会匹配失败,则应从模式串的首位重新开始匹配。

第三种,如果前两情况不满足时,当p[0],...,p[k-1]=[i-k],...p[i-1]且p[k]!=p[i],k>=1,则next[i] =k-1。表明如果模式串当前位置之前的一个子串与模式串的首位开始的一个子串相等,如果模式串当前位置匹配失败,但是模式串匹配失败位置之前子串是匹配成功的,且与模式串首位开始的子串是匹配的,所以应相应从模式串的首位开始的子串的结束位开始匹配。

以下改进后的KMP算法的Java源码:

  1. /** 
  2.  *  
  3.  * @author newstar 
  4.  * @since 2011-09-27 
  5.  * 
  6.  */  
  7. public class KMP2 {  
  8.   
  9.       
  10.     public int match(String p,String t){  
  11.         String pattern = p;  
  12.         String text = t;  
  13.         int i = 0, j = 0;  
  14.         int[] next = calculate_next(pattern);  
  15.         while(i < pattern.length()&& j <text.length()){  
  16.             if(i==-1|| pattern.charAt(i)==text.charAt(j)){  
  17.                 ++i;  
  18.                 ++j;  
  19.             }  
  20.             else{  
  21.                 i = next[i];  
  22.             }  
  23.         }  
  24.         if(j > pattern.length())   
  25.             return j-pattern.length();  
  26.         else return 0;  
  27.     }  
  28.       
  29.     public int[] calculate_next(String pattern){  
  30.         int m = pattern.length();  
  31.         int[] next = new int[m];  
  32.         next[0] = -1;//next[i]=-1时表示主串当前位的下一位与模式串的第0位(首位)进行比较,   
  33.         //即表示主串的当前位置应加1,模式串的当前位置应为首位(第0位)   
  34.         System.out.println("i="+0+" "+"-1");  
  35.         int i = 1,j = 0;  
  36.         while(i<m){  
  37.             if(pattern.charAt(i)==pattern.charAt(0)){//j=0,第二种情况   
  38.                 next[i] = -1;  
  39.                 System.out.println("i="+i+" "+next[i]);  
  40.                 i++;  
  41.                 j++;  
  42.             }  
  43.             else if(pattern.charAt(i)!=pattern.charAt(j)){  
  44.                 next[i] = j;  
  45.                 System.out.println("i="+i+" "+next[i]);  
  46.                 i++;  
  47.                 j = 0;  
  48.             }  
  49.             else {  
  50.                 if(pattern.charAt(i)==pattern.charAt(j)){  
  51.                     i++;  
  52.                     j++;  
  53.                 }  
  54.                 next[i] = 0;  
  55.                 System.out.println("i="+i+" "+next[i]);  
  56.             }  
  57.         }  
  58.         return next;  
  59.     }  
  60.   
  61.     /** 
  62.      * @param args 
  63.      */  
  64.     public static void main(String[] args) {  
  65.         // TODO Auto-generated method stub   
  66.         String pattern = "abcfdabceg";  
  67.         String text = "egaababcfdabcegeabcbcae";  
  68.         KMP2 run = new KMP2();  
  69.         int position = run.match(pattern,text);  
  70.         System.out.println(position);  
  71.     }  
  72. }  
分享到:
评论

相关推荐

    2.KMP算法:高效字符串匹配算法详解

    KMP算法(Knuth-Morris-Pratt算法)是一种高效的字符串匹配算法,由Donald Knuth、Vaughan Pratt和James H. Morris共同发明。KMP算法通过使用一个称为“部分匹配表”或“next数组”的数组来减少字符串匹配过程中的...

    模式匹配的KMP算法详解.

    #### 一、KMP算法背景及传统模式匹配算法 KMP算法,即Knuth-Morris-Pratt算法,是由Donald E. Knuth、James H. Morris和Vaughan R. Pratt三位计算机科学家在1977年共同提出的一种高效的字符串匹配算法。它在模式...

    KMP算法详解.doc

    KMP字符串模式匹配算法是一种高效的字符串模式匹配算法,能够在一个字符串中快速地定位另一个字符串。该算法的时间复杂度为O(m+n),远远优于简单匹配算法的时间复杂度O(m*n)。 二、简单匹配算法 简单匹配算法是一...

    字符串模式匹配KMP算法详解.doc

    朴素模式匹配算法的时间复杂度为O(m*n),而KMP算法通过避免不必要的回溯,将其时间复杂度降低到O(m+n),其中m为主串长度,n为模式串长度。这意味着在最坏情况下,每个字符只需要被检查一次,大大提高了匹配效率。 #...

    KMP算法:高效字符串匹配算法详解

    KMP算法(Knuth-Morris-Pratt算法)是一种高效的字符串匹配算法,由Donald Knuth、Vaughan Pratt和James H. Morris共同发明。KMP算法通过使用一个称为“部分匹配表”或“next数组”的数组来减少字符串匹配过程中的...

    KMP_字符串模式匹配算法

    **KMP字符串模式匹配算法详解** KMP(Knuth-Morris-Pratt)算法是一种高效地在主串(text)中查找子串(pattern)的字符串模式匹配算法,由Dijkstra、Morris和Pratt在1970年提出。这个算法避免了不必要的字符比较,...

    java 中模式匹配算法-KMP算法实例详解

    "java 中模式匹配算法-KMP 算法实例详解" 在 Java 中,模式匹配算法是一种常用的字符串匹配算法,KMP 算法是一种高效的模式匹配算法。下面是 KMP 算法的知识点总结: 1. 朴素模式匹配算法的缺陷:朴素模式匹配算法...

    KMP模式匹配算法c源码.zip

    《KMP模式匹配算法C语言实现详解》 KMP(Knuth-Morris-Pratt)模式匹配算法是一种在文本字符串中高效查找子串的算法,由Donald Knuth、 Vaughan Pratt和James H. Morris三位学者于1977年提出。在计算机科学中,尤其...

    串的模式匹配算法--KMP算法演示示例

    KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,主要用于在主串(目标字符串)中查找模式串(待查找的子串)的出现位置。该算法由Donald Knuth、Vaughan Pratt和James H. Morris三位学者于1970年提出。...

    KMP算法详解 KMP算法详解

    KMP算法,全称为Knuth-Morris-Pratt算法,是一种高效的字符串匹配算法,由Donald Knuth、Vaughan Morris和Robert Pratt三位学者提出。它的主要目标是在一个长字符串(主串A)中查找是否存在一个指定的短字符串(模式...

    模式匹配 经典算法详解

    本主题将深入探讨两种经典的模式匹配算法:AC自动机(Aho-Corasick算法)和KMP单模式匹配算法。 首先,我们来理解KMP算法。全称为Knuth-Morris-Pratt算法,它主要用于在一个长字符串(主串)中查找一个短字符串...

    模式匹配的KMP算法详解

    总结起来,KMP算法的关键在于构建next数组,并利用其指导匹配过程,避免无效的回溯,提高了字符串模式匹配的效率。理解和计算next数组是掌握KMP算法的基础,对于解决字符串匹配问题具有重要的实践价值。

    KMP算法详解KMP算法详解

    KMP 算法详解 KMP 算法是字符串模式...KMP 算法是一种高效的字符串模式匹配算法,广泛应用于文本搜索、模式识别等领域。该算法的核心思想是利用已经得到的部分匹配信息来进行后面的匹配过程,时间复杂度为 O(m+n)。

    KMP字符串匹配算法

    **KMP字符串匹配算法详解** KMP(Knuth-Morris-Pratt)字符串匹配算法是由D.E. Knuth、V.J. Morris和J.H. Pratt三位学者于1977年提出的,它是一种高效的字符串搜索算法,主要用于在一个主串(text)中查找是否存在...

    KMP算法详解-彻底清楚了.pdf

    4. **优化匹配**:通过前缀函数,KMP算法可以跳过部分不必要的比较,使得在最坏情况下,时间复杂度达到O(n + m),其中n是主串长度,m是模式串长度,优于朴素的暴力匹配算法的O(n*m)。 5. **代码实现**:在编程实现...

    深入串的模式匹配算法(普通算法和KMP算法)的详解

    算法的时间复杂度为O(m*n),算法如下: 代码如下://朴素的串的模式匹配算法,S为主串,T为模式串,即找S中有没有与T相同的字串int Index(char *S, char *T, int pos)//pos记录从哪一位开始匹配可以直接用0代替{ ...

    【课件】4.2.1_朴素模式匹配算法.pdf

    ### 朴素模式匹配算法知识点详解 #### 一、朴素模式匹配算法概述 朴素模式匹配算法是一种基础的字符串匹配算法,其基本思想是将一个模式串(即待查找的字符串)在主串(即待搜索的大字符串)中进行逐个字符比较,...

    KMP.rar_KMP_KMP算法_串 KMP算法_字符串匹配

    《KMP算法详解——高效字符串匹配的秘密》 在信息技术领域,字符串处理是极其常见的操作,尤其是在文本分析、数据挖掘和模式识别中。其中,字符串匹配是核心问题之一,而KMP(Knuth-Morris-Pratt)算法正是解决这一...

    数据结构KMP算法配图详解

    总结,"数据结构KMP算法配图详解"的学习资料将帮助你深入理解KMP算法的原理和实现,结合C语言与Java的实例,能够更好地掌握这一重要的字符串匹配技术。通过图文并茂的方式,你将能够更加直观地看到算法的运行过程,...

    kmp算法详解及练习

    KMP算法的核心在于避免了传统字符串匹配算法中出现的不必要的回溯操作,即当模式串的一部分与主串匹配失败时,能够快速确定下一步应该从模式串的哪个位置开始继续匹配,而不是简单地回退到之前的匹配位置重新开始...

Global site tag (gtag.js) - Google Analytics