• KMP算法的实现详解



    1.KMP算法

    1.概念

    KMP是一种改进的字符串匹配算法,该算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。 具体实现通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。

    2.与BF(暴力算法)的的区别

    暴力算法:模拟实现strstr函数
    当信息匹配失败时,主串i不会回退,子串j也不会回到0号位置

    在这里插入图片描述

    3.分析

    1.j的回退位置

    在这里插入图片描述

    在下标为5时,信息匹配失败,此时i不回退,在此匹配失败,说明 主串i与子串j下标5之前一定有一部分是相同的,此时j回退到 下标为2的位置,继续向后就能匹配成功。

    2.next数组

    next[j]=k来表示,不同的 j 对应一个k值,k为要移动的 j 要移动的位置

    寻找k规则:
    1.匹配成功部分的两个相等的真子串(不包含本身),一个以下标0开始,另一个以j-1下标开始结尾。
    2.规定 next[0]=-1 ,next[1]=0, 正式计算是从下标2开始。

    3.next数组的练习

    1.练习1

    在这里插入图片描述

    在这里插入图片描述

    注意事项

    在这里插入图片描述

    2.练习2

    在这里插入图片描述
    在这里插入图片描述

    注意事项

    在这里插入图片描述

    一个小细节:一般来说next数组下标 只会一个一个数加 或者被赋值成0

    4.推导过程

    在next[i]=k的前提下
    在这里插入图片描述

    1.p[i]==p[k]

    在p[0]…p[k-1] p[i-k]==p[i-1] , next[i]=k的前提下
    …p[0]…p[k-1] p[k] == p[x]…p[i-1] p[i] , next[i+1]=k+1

    2.p[i]!=p[k]

    在这里插入图片描述
    回退到下标为2的位置,发现此时p[i]!=p[k],则从当前位置继续回退,
    直到p[i]==p[k],再通过next[i+1]=p[k+1], 确定p[i+1]对应的next下标数

    4.代码实现

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include
    #include
    #include
    //str代表主串
    //sub代表子串
    //pos代表从当前位置
    void getnext(char* sub,int*next,int lensub)
    {
    	next[0] = -1;
    	next[1] = 0;
    	int i = 2;//下一项
    	int k = 0;//前一项的k
    	while (i < lensub)
    	{
    		if (k==-1||sub[i - 1] == sub[k])//当k==-1时,说明第一个数不符合条件,进入循环后next[i]会被置成0
    		{
    			next[i] = k + 1;
    			i++;
    			k++;
    		}
    		else
    		{
    			k = next[k];
    		}
    	}
    }
    int KMP(char* str, char* sub, int pos)
    {
    	assert(str != NULL && sub != NULL);
    	int i = pos;
    	int j = 0;
    	int lenstr = strlen(str);//主串长度
    	int lensub = strlen(sub);//子串长度
    	int* next = (int*)malloc(sizeof(int) * lensub);
    	assert(next != NULL);
    	getnext(sub,next, lensub);
    	while (i < lenstr && j < lensub)
    	{
    		if (j==-1||str[i] == sub[j])//当一个数不符合条件时,此时就需要加入一个条件,否则就会造成越界
    		{
    			i++;
    			j++;
    		}
    		else
    		{
    			j = next[j];
    		}
    	}
    	if (j >= lensub)
    	{
    		return i - j;
    	}
    	return -1;
    }
    int main()
    {
    	char s1[40];
    	char s2[40];
    	scanf("%s%s", s1, s2);
    	printf("%d\n", KMP(s1,s2,0));
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    1.代码的注意事项
    1.next数组值为-1时

    在这里插入图片描述
    在这里插入图片描述

    当此时的p[i]!=p[k]时,一直通过next数组值返回到前面的p所在,但到第一个数依旧p[i]!=p[k]时,
    则会将k置成-1,进入if循环后 k值为0 即 此位置的next所在下标为0

    2.k值为-1时

    在这里插入图片描述

    在这里插入图片描述

    只有第一个数对应next数组的值为-1,说明主串与子串第一个数就信息匹配失败
    而在if循环中如果不加入j==-1的判断 ,只有 sub[i]==sub[j],则会造成越界

    2.KMP算法的优化

    关于next数组的优化
    在这里插入图片描述
    若在下标为5的位置信息匹配失败,就会一直回退,直到下标为0的位置
    优化的目的就会使 此时直接找到下标为0的位置

    1.规则

    如果回退到的位置和当前字符一样,就写回退那个位置的nextval值
    如果回退到位置和当前字符不一样,就写当前字符原来的nextval值

    2.练习题

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Redis高可用之主从复制原理演进分析
    圆梦字节之后,我收集整理了这份“2021秋招常见Java面试题汇总”
    python+vue+elementui心理健康测试教育系统django339
    Ubuntu 20.04降级clang-format
    PostgreSQL数据库缓冲区管理器——本地缓冲区管理
    我们该如何看待AIGC(人工智能)
    目标检测系列算法:YOLOv6代码复现
    集合—Map接口实现类-HashMap
    Day55 web框架 入门 Django
    C++环形缓冲区
  • 原文地址:https://blog.csdn.net/qq_62939852/article/details/126832628