KMP算法详解

==> 学习汇总(持续更新)
==> 从零搭建后端基础设施系列(一)-- 背景介绍


next数组生成请看 KMP算法next数组详解

KMP算法步骤如下:
假设主串是: “ABABBABABABB”
模式串是: “ABABABB”
移动位数的计算公式为:移动位数 = 已匹配字符数 - 部分匹配值(next数组)
1.获取next数组。
next[0]=-1,next[1]=0,next[2]=0,next[3]=1,next[4]=2,next[5]=3,next[6]=4
2.从第一个字符开始比较,当比到str[4] != subStr4,查找前一个字符的部分匹配表信息next[4] == 2,前面已经匹配了4个字符,所以移动4-2=2位。如图所示:
KMP算法详解_第1张图片

3.接着str[4]和subStr[2]比较,也匹配失败,再次查询next数组得j=next[2] == 0。模式串往后移2-0=2位。
KMP算法详解_第2张图片

4.接着str[4]和subStr[0]比较,也匹配失败,再次查询next数组得j=next[0] == -1。当j==-1的时候,模式串就要往后移一位。
KMP算法详解_第3张图片

5.后面的匹配就都成功了。

详细代码:

/*
* function			给定一个子串,在主串中查找其起始位置(KMP算法)
* param    str		主串
* param    substr	模式串,也就是子串
* param    pos      从主串的哪个位置开始匹配
* return            成功返回匹配的起始位置,失败返回-1
*/
int Kmp(char* str, char* subStr, int pos)
{
	int iLen1 = strlen(str);
	int iLen2 = strlen(subStr);
	if (pos < 0 || pos >= iLen1 - iLen2)  //pos的位置不能为负的,否则越界
		pos = 0;						  //如果pos不合适,则自动设置为0
	int* next = (int*)malloc(sizeof(int)*iLen2);
	GetNext(subStr,next ,iLen2);   //获取next数组
	int i = pos, j = 0; //i是主串的下标,j是模式串的下标

	/*
	例如 主串是:ABABBABABABB,模式串是ABABABB,其中j==-1的作用和GetNext函数中一样的,
	     都是若前面无任何字符匹配的时候,进行往后移一位

		 移动位数的计算公式为:移动位数 = 已匹配字符数 - 部分匹配值(next数组)

		 1.一开始比较的是str[0]和subStr[0]('A'和'A'),相等,继续往后比较

		 2.当i=4,j=4的时候,str[4]!=subStr[4]('B'!='A'),不相等,将j置为next[j](j=next[4] == 2)
		   意思是,模式串往后移动4 - 2 = 2位

		 3.i=4,j=2,str[4]!=subStr[2]('B'!='A'),不相等,将j置为next[j](j=next[2] == 0)
		   意思是,模式串往后移动2 - 0 = 2位
         
		 4.i=4,j=0,str[4]!=subStr[0]('B'!='A'),不相等,将j置为next[j](j=next[0] == -1)
		   这里就是j==-1的作用了,当j==-1直接就往后移一位。

		 5.i=5,j=0,str[5]!=subStr[0]('A'=='A'),相等,继续往后比较

		 6.最后i=11,j=6,str[11]!=subStr[6]('B'=='B'),相等,并且j == iLen2,返回i-j=5
	*/
	while (i < iLen1)
	{
		if (j == -1 || str[i] == subStr[j])
		{
			++i,++j;
			if (j == iLen2)//匹配完成就返回匹配的首位置
				return i - iLen2;	
		}
		else
			j = next[j];              
	}
	return -1;   //找不到则返回-1
}

现在来比较一下BF和KMP的效率

1、模式串随机产生的情况下

随机产生10亿个字母(A-Z),测试如图:
1)、模式串长度为10
KMP算法详解_第4张图片

2)、模式串长度为100
KMP算法详解_第5张图片

3)、模式串长度为1000
KMP算法详解_第6张图片

4)、模式串长度为10000
KMP算法详解_第7张图片

2、模式串前缀后缀重合很大的情况下

产生1亿个A字母,然后最后一个字母是B
1)、模式串长度为10
KMP算法详解_第8张图片

2)、模式串长度为100
KMP算法详解_第9张图片

3)、模式串长度为1000
KMP算法详解_第10张图片

4)、模式串长度为10000
KMP算法详解_第11张图片

从测试结果看,一般情况下,BF算法的效率比KMP效率要高,当前缀后缀重合比较大的时候,KMP效率比BF效率就高很多。BF算法的最好情况甚至可以达到0(n),最坏才0(nm)。例如:主串是AAAAA……AAAAABC,模式串是BC,则时间复杂度就是0(n),若模式串是AA……AAB,则时间复杂度就是0(nm)。













KMP算法next数组详解
顺序表的动态增长(C++、JAVA)

栈、递归、循环的关系(C++、JAVA)

栈应用之中缀转后缀表达式计算(C++、JAVA)

栈应用之中缀转后缀表达式(C语言版)

约瑟夫问题详解+源码

线性表之循环队列

线性表之链队列

线性表之顺序队列

线性表之链栈

线性表之顺序栈

线性表之双向链表

线性表之循环链表

线性表之单链表

线性表之顺序表

你可能感兴趣的:(数据结构,kmp,next数组,算法,数据结构,字符串)