您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

字符串匹配KMP算法

时间:2020-05-06 12:21:49  来源:  作者:

什么是KMP

KMP(D.E.Knuth,J.H.Morris,V.R.Prat)是三个发明者的名字首字母命名的。用于字符串匹配的经典算法。

常规匹配算法

这个算法很抽象,研究了些时间才慢慢弄懂里面的一些奥秘之处,并借此记录下来,以便后期回顾。

常规字符串匹配方式:

主串:ABC ABCDAB ABCDABCDABDE

模式串:ABCDABD

我们要在主串里查找匹配串是否存在,那么常规匹配方式如下:

主串和模式串都从头开始匹配,当出现不匹配的字符时,如图1所示,主串A字符和模式串的D字符不匹配,那么说明主串A开头和模式串不匹配,主串往后移从B字符开始重新和模式串进行比较(如图2)。因为主串B和模式串A不相等,所以主串往后移继续和模式串比较(如图3),重复以上操作,知道在主串中找到对应的字串或者找不到。但是这样比较的效率十分低,当出现不相等就会对模式串复位,然后从头开始比较。要想比较速度加快,不用每次模式串都是从头开始比较,下面介绍的KMP算法,就可以做到。

字符串匹配KMP算法

图1

 

字符串匹配KMP算法

图2


字符串匹配KMP算法

图3

 

KMP实现

KMP的思想是当主串和模式串不相等时

1.主串不用像常规匹配那样,需要从上一次的下一个位置开始重新和模式串进行匹配,保持当前位置不变和已经移动过的模式串进行匹配,如果模式串移动的字符为0并且第一个字符和主串的当前字符也不相等,那么主串需要往后移动一个字符继续和模式串匹配。

2.模式串将已经对比过的好前缀一次性往后移动多个字符。

如图4,当主串的空格和模式串的D不相等时,主串位置保持不变,模式串不用从0下标开始,而是从下标2开始重新匹配。因为ABCDAB主串和模式中进行对比后是相等的,那么,坏字符D的最长前缀和后缀集合是AB,长度为2。

模式串的起始位置依赖一张表叫部分匹配表。

字符串匹配KMP算法

图4

部分匹配表:

字符串匹配KMP算法

图5

部分匹配表是根据好前缀和好后缀共有元素的长度

A 前缀和后缀的集合为空 共有元素长度为0

AB 前缀【A】,后缀【B】 共有元素长度为0

ABC 前缀【A,AB】,后缀【BC, C】 共有元素长度为0

ABCD 前缀【A,AB,ABC】,后缀【BCD,CD,D】 共有元素长度为0

ABCDA 前缀【A,AB,ABC,ABCD】,后缀【BCDA,CDA,DA,A】 共有元素长度为1

ABCDAB 前缀【A,AB,ABC,ABCDA】,后缀【BCDAB,CDAB,DAB,AB,B】 共有元素长度为2

ABCDABD 前缀【A,AB,ABC,ABCDAB】,后缀【BCDABD,CDABD,DABD,ABD,BD,D】 共有元素长度为0

 

在程序中部分匹配表可以使用一个数组来保存,可以命名为next数组,next数组的下标为当前正在和主串进行比较的字符下标,其值是当前字符的好前缀和好后缀共有元素的长度。

我们约定next[0]为-1,那么上面的部分匹配转换成next数组如下:

next[0]=-1 A A字符的好前缀和好后缀共有元素长度为0

next[1]=0 AB B字符的好前缀和好后缀共有元素长度为0

next[2]=0 ABC C字符的好前缀和好后缀共有元素长度为0

next[3]=0 ABCD D字符的好前缀和好后缀共有元素长度为0

next[4]=1 ABCDA A字符的好前缀和好后缀共有元素长度为1

next[5]=2 ABCDAB B字符的好前缀和好后缀共有元素长度为2

next[6]=0 ABCDABD D字符的好前缀和好后缀共有元素长度为0

 

代码实现:

//s:模式串   len:模式串长度   next:next数组保存部分匹配表数据
void getNext(char *s, int len, int *next){
    int k = -1; //模式串s下标j的前后缀共有元素长度
    int j = 0;  //模式串的下标
    next[0] = -1;//第一个元素的共有元素约定为-1
    while(j < len){
        if(k == -1 || s[k] == s[j]){//k=-1表示是第一个字符
            //如果前缀和后缀有共有元素,那么前缀和后缀都后移一个字符,然后再次比较。
            k++;
            j++;
            next[j] = k; //将当前字符的前缀和后缀共有元素长度保存到next数组
        }else{
            k = next[k]; //如果不等,那么前缀字符串根据next数组往前查找和当前字符为后缀匹配的位置,
                               //如果一直找不到那么k值将会变成成0。就是说主串要从模式开头进行匹配。
        }
    }
}

 

有了计算next数组的算法,那么KMP的实现就很简单了

/*
*s:主串   slen:主串长度   p:模式串  plen:模式串长度   next:已经计算过的next数组   res:匹配的下标位置
*
*/
int kmp(char*s , int slen, char*p, int plen, int *next, int *res){
    int s_index, p_index=0, res_index=0;
    for(s_index = 0; s_index < slen; s_index++){
            while(p_index > 0 && s[s_index] != p[p_index]){
                    //下一个匹配位为next数组的第j-1位
                    p_index = next[p_index-1]+1;
            }
            if(s[s_index] == p[p_index]){
                    p_index ++;//如果相等就都往后移一位
            }
            //如果匹配串的第一位一直和模式串第一位不相等,那么模式串id s_index一直往后移
            if(p_index == plen){
                    res[res_index++] = s_index-p_index+1;//应为当模式串和匹配串相等时,匹配串的下标会加1,所以会多减1,后面要加上
                    p_index = 0;
            }
    }
    return res_index;
}

 

说明: 以上仅仅代表自己的想法。



Tags:KMP算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  Tags: KMP算法  点击:(36)  评论:(0)  加入收藏
什么是KMPKMP(D.E.Knuth,J.H.Morris,V.R.Prat)是三个发明者的名字首字母命名的。用于字符串匹配的经典算法。常规匹配算法这个算法很抽象,研究了些时间才慢慢弄懂里面的一些...【详细内容】
2020-05-06  Tags: KMP算法  点击:(61)  评论:(0)  加入收藏
只要你学过数据结构与算法分析,相信你对KMP算法应该都不陌生吧?如果你没听过,不要紧,今天我们就来聊一聊这个算法。建议最好拿一张草稿纸,然后边看边理解,这样更有助于你对它的理...【详细内容】
2020-04-07  Tags: KMP算法  点击:(45)  评论:(0)  加入收藏
字符串匹配是计算机的基本任务之一。举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"?许多算法可以完成这个任务,(简称KMP)是最常用...【详细内容】
2019-09-29  Tags: KMP算法  点击:(89)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(11)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(22)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(14)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(40)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条