对KMP算法小理解

一.KMP算法

1.用途

KMP算法主要用于字符串的匹配问题。
例如:
在这里插入图片描述

  1. 第一种办法是暴力解法,依次遍历寻找,在文本串中找到第一次与模式串第一个字符相等的字符后,依次遍历如果文本串中出现与模式串不相等的字符,然后再从文本串的下一个字符再遍历出与模式串相等的字符,再遍历下面的是否与模式串相等,直到全部相等为止。这样看出是非常复杂而且时间复炸度是很高的。

  2. 第二种办法是KMP算法很好的解决了复杂度高的问题,先开始遍历文本串与模式串,当文本串中出现与模式串不相同的字符时,它会跳到模式串的第一个字符与文本串不相同的字符之间,再与该文本串的字符进行比较。
    如上面的例子。文本串中的位置不变,只是模式串中的位置变了。
    在这里插入图片描述

那怎样可以使模式串从f跳到b呢?这里需要建立一个next[]数组。

2.next数组建立

1.前缀表

  • 前缀:包含首字母,不包含尾字母的所有字串。
  • 后缀:包含尾字母,不包含首字母的所有字串。
    在这里插入图片描述
    前缀表求的使两字符串之间,前缀与后缀相等的最长字串的长度。next数组中保存的数据就是模式串中,从0号下标开始到最后一个下标的字符的最长字串的长度。

在这里插入图片描述
next数组中保存的就是前缀与后缀中最长子串的长度。如上面例子next[]={0,1,0,1,2,0};

那它是如何从模式串的f跳到b的呢?
已知next数组个数与模式串中的有效字符个数相等,当模式串中的字符f与文本串中的字符不相等时,它会将next[模式串中与文本串字符不相等的下标-1]的值
作为下标赋给模式串。这样就实现了模式串冲f跳到b。
比如上面例子中:模式串与文本串不相等字符f下标为5,然后next就会将next[5-1]=2作为下标赋给模式串,即  模式串[2]。再与文本串中的字符进行比较。

2.next数组用代码实现

因为next数组里放的模拟串前缀与后缀相等的最长字串的长度,所以讨论的时模拟串前缀和后缀。

  • 思想:
    首先要建立两个变量,i(后缀尾),j(前缀尾和前缀与后缀相等的最长字串的长度)注意j有两层含义。
    然后进行初始化。
    再讨论前缀尾与后缀尾不相等的情况。这个必须先考虑,因为当前缀与后缀相等时再来更新j。
    最后讨论前缀尾与后缀尾相等的情况。
void Getnext(int *next, const char *p){
	int j = 0;
	next[0] = 0;//一开始初始化为0,因为一开始没有前缀和后缀。
	for (unsigned int i = 1; i < strlen(p); i++){
		while (p[i] != p[j] && j>0){//注意是循环,依次找前缀尾是否与后缀尾相等,直到相等或到了最开始的位置。
			j = next[j - 1];//回退是回退到next[j-1]处
		}      //这个必须在相等上面,直到找到相等的才退出更新j。
		if (p[i] == p[j]){
			j++;
		}
		next[i] = j;
	}

}

个人的理解为什么跳到上一个next数的位置,
在这里插入图片描述

理解next数组怎么来的,需手画一下,或者看链接。
或者看着链接:https://www.bilibili.com/video/BV1PD4y1o7nd
https://www.bilibili.com/video/BV1M5411j7Xx

3.用KMP算法实现strstr函数

#include<stdio.h>
void Getnext(int *next, const char *p){
	int j = 0;
	next[0] = 0;
	for (unsigned int i = 1; i < strlen(p); i++){
		while (p[i] != p[j] && j>0){
			j = next[j - 1];//这个必须在相等上面,直到找到相等的才退出更新j。
		}
		if (p[i] == p[j]){
			j++;
		}
		next[i] = j;
	}

}

int Mystrstr(const char *arr, const char *p){
	int *next = (int *)malloc(sizeof(int)*strlen(p));
	Getnext(next, p);
	int j = 0;
	for (unsigned int i = 0; i<strlen(arr); i++){
		while (arr[i] != p[j] && j>0){
			j = next[j - 1];
		}
		if (arr[i] == p[j]){
			j++;
		}

		if (j == strlen(p)){
			return i - strlen(p) + 1;
		}
	}
	return -1;

}
int main(){
	char *arr = "hellow";
	int n = Mystrstr(arr, "ll");
	printf("%d\n", n);
	return 0;
}

返回第一次出现字符串的下标。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值