`

图解Kmp算法

 
阅读更多

前言:最近在复习数据结构,又偶遇kmp,居然没感觉了,理不出思路,特别是对next[]函数的求解更没感觉,于是静下心花了2天时间,细细重新理解了一遍,这篇文章仅当自己在学习kmp过程中的一点感悟,或许不一定理解的完全透彻,只是在记录我学习过程中思维的灵感,以便今后回来感受。好了废话不多说了,直接进入正题。

 

1.什么是kmp?

   它是一种字符串匹配算法。与以往字符串匹配算法的区很简单就是,kmp算法中主串的i值不回溯,子串的j值每次回溯不一定从0开始,它每次回溯值j = next[j].看下面的图就能一清二楚了。

 
     



 

    有了这个两个图:就很容易理解kmp算法了。只要把字符串匹配想象成一个有齿痕的长尺子和一个有齿痕的短尺子,长尺子不动,短尺子在长尺子身上找相同的齿痕,那么要想很快匹配成功的话,那么我们肯定是先找长齿痕与短齿痕最相似的地方先去比较一下,如果发现不匹配,在找相似程度小一点的去比较,然后依次减少相似度慢慢一次次比较下去,直到成功找到。这里我只是为说明kmp算法的核心思维,其具体细节我就没有一一纠结,你们自己可以在纸上用例子去观察观察。具体实现算法我也不想多讲,因为网上很多。 

 

二:关于next[]函数的推导。

 

   可以说kmp算法难就难在next[]的推导,至少我学习的过程中是这么感觉到的。到不是说要自己求出next[]值难,而是难在理解它是怎么找到字符串的相似度的。特别是网上求next[]函数代码的理解,稍后详细解释。

 

首先还是说明一下next[]函数的含义。

  1.首先对kmp算法来讲:next[] 函数是针对子串来讲的。它是求子串中,每一个位置的之前的字符串的相似度。例如:next[j] = k 的含义:就是子串的j个位置之前的字符串的相似度。(求next[]过程中理解)

  子串第j个位置的字符与主串字符不匹配时,下一个匹配的位置为子串第k个位置。(与主串匹配过程中的理解)

 两种理解都可以,前一种理解在求next[]的过程中比较容易。第二种理解比较适合在与主串匹配的过程中。

     网上很多人都是这样理解的:当主串第j位置上的字符与子串不相等时,下一个要匹配的字符就是子串第k个位置的字符。这样讲把j值重点落在主串身上了,要知道子串长度肯定少于子串的,所以如果j值大于子串的长度,那next[]数组不超出范围了吗?所以对于网上这种讲法保留意见。

 

这里说的相似度理解:不是说有相同的就是,而是说的中心对称。例如:abcabc 他们就是。而对于字符串

abcabb 不能说明它们相似。因为他们不是中心对称。可以理解字符串的前辍等于字符串的后辍。下面用一个例子说明问题:

假定一个字符串:

位置: 01234567

子串p:abcabckfg

p[0]位置: 由于a字符前无元素,所以谈不上相似度。所以可以取值为next[0] = -1;(网上也有表示为0的,那是因为它的位置是1234567);

 

 p[1]位置:由于b位置前面的字符串为只有一个a,所以他相似度为next[1]=0;

 

p[2],p[3] 位置之前的字符串分别为:ab,abc 也无相似的。 next[2],next[3] = 0 ;

p[4].位置:字符串为abca   可以看到红色部分相同,即前辍=后辍。next[4] = 1 ;理解:当p[4]位置与主串不匹配时,下一个要匹配的位置即为j = 1.即为b字符。

后面的就不一一推导,原理类似。

 

 

三:关于next[] 数组推导代码理解。

   递归思想:因为已经知道next[0] = -1;next[1] = 0 了。能否推导的出,现在的问题就是能否由

next[j]=k 推出next[k+1]。在推导之前,首先要明确一个问题就是:pj,pk 究竟是表示什么?

 因为网上有文章讲分情况:pj = pk 或者pj!=pk 两种去推导。而且把求解next[]的过程看成是与子串相同的字符串匹配过程,这很让人迷惑的,因为不是求子串的相似度么,为什么要拿相同的来比较?而且理解pj = pk 的过程也不清楚。认为pj 就是子串的的j个位置的字符,pk就是主串的第k个位置的字符。其实这种理解是不恰当的。

先看看代码吧:(网上找的)用代码对照例子说明

void getNext(char *p,int *next)
{
    int j,k;
    next[0]=-1;
    j=0;
    k=-1;
    while(j<strlen(p)-1)
    {
        if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k]
        {
            j++;
            k++;
            next[j]=k;
        }
        else                   //p[j]!=p[k]
            k=next[k];
    }
}

 

假设要求字符串ababdf的next[]数组

字符串:ababdf

位置:    012345

 

因为next[0],next[1] 的值我们都知道了。所以一开始我们求的是next[2] 即第3个位置之前字符串的相似度。要求next[2],即看ab他们的相似度高不高,所以就要比较p[0]是否等于平p[1]。

如图理解:



 当i 等于2时如图:



 后面依次i++,直到i到最后一个字符,这里就不在细说。由代码结合图我们可以知道:每一次比较pi,pj其实是在比较字符串的前辍和后辍。每次判断j位置之前的字符串,看前辍是否等于后辍。 

 

上面的求解代码是经过优化而来,有一定的难度,不理解的同学可以依次跟着程序走将过程画出来,就清楚了,其实就是每次i往前移动时,就是在匹配i之前的那个字符是否和字符串的前辍某个字符相等,如果不相等,j = next[j],j回溯,直到找到,如果当j = 0还是没找到,那么说明该位置没有相等的了。此时next[i] = 0.

其实上面写的求next[]函数代码写的比较精巧,如果求串ababaf的next[]其核心思想就是:如图:



 

如果还是不理解,其实还可以直接求解,不就是比较子串的前辍和后辍相等嘛:

代码如下:

void getNext(char *p,int *next)
{
    int i,j,temp;
    for(i=0;i<strlen(p);i++)
    {
        if(i==0)
        {
            next[i]=-1;     //next[0]=-1
        }
        else if(i==1) 
        {
            next[i]=0;      //next[1]=0
        }
        else
        {
            temp=i-1;
            for(j=temp;j>0;j--)
            {
                if(equals(p,i,j))
                {
                    next[i]=j;   //找到最大的k值
                    break;
                }
            }
            if(j==0)
                next[i]=0;
        }
    }
}
 
bool equals(char *p,int i,int j)     //判断p[0...j-1]与p[i-j...i-1]是否相等  
{
    int k=0;
    int s=i-j;
    for(;k<=j-1&&s<=i-1;k++,s++)
    {
        if(p[k]!=p[s])
            return false;
    }
    return true;
}

 

 其实关于next[] 数组还可以优化,在这里就暂且不讲了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 49.8 KB
  • 大小: 27.6 KB
  • 大小: 25.7 KB
  • 大小: 56.1 KB
  • 大小: 40.8 KB
  • 大小: 67.2 KB
分享到:
评论

相关推荐

    数据结构KMP算法配图详解

    KMP算法主要用于解决字符串匹配问题,尤其在处理大量数据时表现出优越的效率。在这个"数据结构KMP算法配图详解"中,我们将深入探讨该算法的原理、实现以及它在C语言和Java中的具体应用。 1. KMP算法概述: KMP算法...

    【超全!】图解Java数据结构和算法(共195集)【资料+视频+课件+代码+笔记】

    稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、中缀、后缀表达式、中缀表达式...KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法马踏棋盘算法...

    算法图解笔记以及代码文件.zip

    9. **字符串处理**:如KMP算法、Rabin-Karp算法,用于高效地进行模式匹配,对文本处理和搜索引擎设计至关重要。 10. **图论与网络流**:如最大流最小割问题,可以应用于网络调度、资源分配等问题。 压缩包中的笔记...

    藏经阁-图解算法小抄-364.pdf

    接着,它列举了一些经典的面试题,如字符串匹配、动态规划问题,涉及到了暴力匹配、KMP算法、分治策略、回溯算法、深度优先搜索(DFS)以及贪心算法。这些问题的解决不仅要求对算法有深刻理解,还需要具备将算法应用于...

    字符串匹配算法之Horspool算法

    当模式串较短或模式串中字符分布较为均匀时,其搜索效率可能不如其他算法如KMP算法或Rabin-Karp算法。此外,对于包含大量随机字符的文本,Horspool算法的平均搜索速度可能接近于O(n),但在最坏情况下仍可能退化为O...

    数据结构和算法-思维导图.pdf

    - 字符串匹配算法如朴素字符串匹配、RK算法、BM算法、KMP算法、Trie树、AC自动机、后缀数组等。 - 散列列表在字符串处理中的应用。 4. **数据结构类型**: - 线性表查找和树结构查找,广度优先搜索和深度优先...

    《剑指 Offer》 Python, Java, C++ 解题代码,LeetBook《图解算法数据结构》配套代码仓.zip

    10. **字符串处理**:模式匹配、KMP 算法、Trie 树等,对于处理字符串问题至关重要。 通过学习和实践这些代码,不仅可以提高编程能力,还能提升解决问题的思维能力,为面试和实际工作中的问题解决打下坚实基础。...

    各种算法图解

    - **KMP算法**:模式匹配,避免了不必要的回溯。 - **Manacher's Algorithm**:在线性时间内找出字符串中的最长回文子串。 - **Rabin-Karp滚动哈希算法**:用于快速查找字符串模式。 通过详细的图解,这些概念会...

    算法---源文件(主要是算法里提及到的源文件,很详细。)

    5. 字符串匹配:如KMP算法、Boyer-Moore算法,用于文本处理和信息检索。 三、源文件解析 1. 源代码结构:源文件通常包括函数定义、变量声明、控制流结构(if、for、while)、类定义等。 2. 注释:为了便于理解和...

    《Hello 算法》:动画图解、一键运行的数据结构与算法教程,支持 Java

    16. **字符串处理**:KMP算法、Trie树等,用于高效搜索和匹配字符串。 通过这个教程,学习者将不仅能够理解这些数据结构和算法的原理,还能直接运行示例代码,观察它们在实际中的运行效果。这种互动式的教学方法有...

    python算法.zip

    - KMP算法:快速匹配字符串模式,避免不必要的回溯。 - Rabin-Karp算法:通过滚动哈希值进行字符串匹配。 7. **递归与分治**: - 递归:函数直接或间接调用自身解决问题的方法,如Fibonacci序列、阶乘计算。 - ...

    图解几种常用数据结构(PPT)

    图解几种常用数据结构(PPT) ...本文图解了几种常用的数据结构,包括单链表、栈、队列、Trie树、KMP算法和并查集。这些数据结构在实际应用中扮演着重要的角色,了解和掌握这些数据结构是编程的基本功。

    数据结构中的代码,算法和电子笔记,字典,图解

    9. **第七章**:这可能涵盖更高级的主题,如动态数据结构(如伸缩数组、自平衡树)、字符串处理、模式匹配算法(如KMP、Boyer-Moore)或是编码技术(如哈夫曼编码)。 10. **电子笔记**:这部分包含的是学习过程中...

    通俗易懂的数据结构和算法教程(含配套资料)

    3)授课方式采用图解+算法游戏的方式,让课程生动有趣好理解 4)系统全面的讲解了数据结构和算法, 除常用数据结构和算法外,还包括程序员常用10大算法:二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、...

    很好很强大的算法资料

    在算法中,字符串匹配(如KMP、Boyer-Moore算法)和模式匹配问题是很常见的。 这个压缩包的HTML文件很可能是对以上知识点的详细讲解,通过实例和代码展示,帮助学习者深入理解和应用算法。无论是初学者还是经验丰富...

    Java和C语言实现各种经典算法

    6. 字符串算法:KMP匹配、Rabin-Karp匹配、Manacher's Algorithm等。 7. 计数排序、桶排序等非比较排序算法。 每个算法的实现通常会包括详细的注释,帮助理解每一步的作用,同时可能配以图例,以直观地展示算法的...

    算法 第四版

    但是瑕不掩瑜,对于绝大部分内容真的讲的超级清楚,完美的图解,就像单步调试一样,也许是一本不需要智商就能看懂的算法书(习题应该略有难度,还没有做,打算上Princeton的公开课时同步跟进)。至少这是一本让我这个...

    图解数据结构 7个压缩包合一

    9. 字符串:字符串是字符序列,处理字符串的算法包括模式匹配、字符串搜索(如KMP算法)和字符串匹配问题。 通过"图解数据结构"这样的资源,学习者可以深入理解这些概念,看到它们如何工作,以及如何在实际问题中...

    Algorithms 4th Edition.pdf

    - 字符串匹配算法,如 KMP 算法。 - 正则表达式和自动机理论。 6. **数值算法**: - 数学函数计算、随机数生成等。 - 复杂数值问题的解决方法。 #### 四、特色与优势 - **深入浅出**:书中通过大量的示例和...

    LeetCode 刷题攻略:配思维导图,100+经典算法题目刷题顺序、经典算法模板-Python开发

    LeetCode 刷题攻略:配思维导图,100+经典算法题目刷题顺序、经典算法模板、共40w字的详细图解,以及难点视频题解。按照刷题攻略上的顺序来刷题,让你在算法学习上不再迷茫! 目录: 算法面试思维导图 B站算法视频...

Global site tag (gtag.js) - Google Analytics