kmp匹配算法介绍及实现

KMP匹配算法

最近在看程杰的《大话数据结构》一书,看到了第五章,这一章介绍了对串进行匹配的算法,包括朴素模式匹配算法和KMP模式匹配算法。对于KMP算法自己也是搞得有点晕乎了,在这里记录下,以后说不定彻底弄懂了就回来补上。

  • KMP算法是由D.E.Knuth、J.H.Morris和V.R.Pratt三位前辈共同发表的一个模式匹配算法,该算法可以大大避免重复遍历的情况。

  • 我们把要查找的字符串称为模式串pattern,相应的在某个字符串中进行查找是否包含模式串的称为文本串text,也称为主串。

  • KMP算法的核心是前缀表,也称为next数组的计算,next数组里面存放的是模式串的最长前后缀的相似度。所谓前后缀是指模式串中的某个子串,而最长前缀是指:该子串第一个字符开始,不包含最后一个字符的串,而最长后缀是指:该子串不包含第一个字符的串。

例子

比如模式串为abcabcd,其前缀分别是:
a
ab
abc
abca
abcab
abcabc
abcabcd
这些前后缀的相同的最长前后缀分别是:
0
0
0
1---->a
2---->ab
3---->abc
0
所以next数组的值是{0, 0, 0, 1, 2, 3, 0} 。

代码实现

  • 以上便是自己理解的部分,下面是实现代码:

    获取前缀表:   
       void get_prefix_table(const char *pPatternStr, int *next)
       {
            if(NULL == pPatternStr) return;
          	
          	int i = 1;
          	int j = 0;
          	int len = strlen(pPatternStr);
          	
          	if(len == 0) return;
          	
          	next[0] = 0; //规定是0
          	
          	while(i < len)
          	{
          		if(pPatternStr[j] == pPatternStr[i])
          		{
          			j++;
          			next[i] = j;
          			i++;
          		}
          		else
          		{
          			if(j > 0)//防止数组越界
          			{
          				j = next[j-1]; //回溯
          			}
          			else
          			{
          				next[i] = 0;  
          				i++; //移动到下一位继续
          			}
          		}
          	}
          	for(i=len-1; i>0; i--)//next数组往后移动一位,便于KMP算法匹配实现
          	{
          		next[i] = next[i-1];
          	}
          	next[0] = -1;
            }  
         
          /*
          KMP算法实现
          字符串匹配
          main_str: 主串
          sub_str: 子串
          pos: 从主串main_str的第pos位开始往后查找与子串sub_str相匹配的串
          return: 返回子串sub_str相匹配的第一个串的起始位置, 没有匹配则返回-1
          */
          int kmp_search(const char *main_str, const char *sub_str, int pos)
          {
          	if(pos<0 || !main_str || !sub_str) return -1;
          	
          	int i = pos;
          	int j = 0;
          	int main_len = strlen(main_str);
          	int sub_len = strlen(sub_str);
          	
          	if(pos>main_len || !sub_len || !main_len) return -1;//越界或者空字符串
          	
          	int *next = (int *)malloc(sizeof(int) * sub_len);
          	
          	get_prefix_table(sub_str, next);
          	
          	while(i<main_len && j<sub_len)
          	{		
          		if(j == sub_len-1 && main_str[i] == sub_str[j])
          		{
          			free(next);
          			return i-j;
          		}
          		if(main_str[i] == sub_str[j])
          		{
          			i++;
          			j++;
          		}
          		else
          		{
          			j = next[j];
          			if(-1 == j)
          			{
          				i++;
          				j++;
          			}
          		}
          	}
          	free(next);
          	return -1;
          }
    
  • 最后附上一个视频讲解教程:
    http://www.bilibili.com/video/av26071816

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值