《数据结构和算法》之KMP算法

一,KMP算法

       KMP算法,全称就是克努特-莫里斯-普拉特算法,是为了避免大量的重复遍历的情况。举个例子:

                                   

                                                                                                        图 1 遍历对比匹配图1

                                    

                                                                                                        图2 遍历对比匹配图2

          从图1和图2中可以看出来,在图1中如果依次匹配,到5的时候匹配不成功,此时要回头重新匹配,从i=2,j=1的位置开始匹配,这就是回溯法的思想,就这样依次来回地回溯对比验证,最后才给出一个结论是否匹配成功。

                                   

                                                                                                               图 3  思路启发一

       思路启发一,在图3中可以看到在上面的匹配中,当i=j=5的时候,是S[5]与T[5]不相等,即不匹配,此时要重新进行匹配,分析可知S[1]=T[1],S[2]=T[2],S[3]=T[3],S[4]=T[4],而T[1]不等于T[2],T[1]不等于T[3],T[1]不等于T[4],T[2]也不等于T[3],T[2]也不等于T[4],此时就不用将T[1]与S[1]\S[2]\S[3]\S[4]相匹配,直接让T[1]与S[5]进行匹配,即如图3下面的演示那样。这个时候提高了效率。

                                   

                                                                                                     图4  思路启发二

         这个思路启发二看上去肯定不符合启发一的情况,此时T[1]与S[2]是相等的,T[1]=T[2],这个时候可以直接认为T[1]=S[2],匹配下一个,即匹配T[2]与S[3],依次匹配下去就会出现匹配成功的结果。

                                  

                                                                                                        图 5   思路启发三   

        在图5中可以看到,T[1]=T[2]=S[4]=S[5],此时可以直接从T[3]开始匹配,这样就提高了效率。

                                   

                                                                                                      图6  思路启发四

          在图6思路启发四中可以看到,根据前面的一二三的经验这个时候可以很明显从T[4]开始匹配。这样得出的一些规律就是KMP算法。问题是由模式串决定的,而不是目标串决定的。主要是为了保证 i 不再回溯。避免了效率低下的问题。

二,KMP算法的实现

       1,首先get_next函数的编写

                   

#include <stdio.h>

typedef char* String;

void get_next(String T,int *next)
{
	int i = 1;
	int j = 0;
	next[1] = 0;
	
	while(i < T[0])
	{
	    if(0 == j || T[i] == T[j])
		{
		     i++;
			 j++;
			 next[i] = j;	
		}	
		else
		{
		     j = next[j];	
		}
	}
}

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main() 
{
	char str[255] = "ababaaaba";
	int next[255];
	int i = 1;
	
	str[0] = 9;
	
	get_next(str, next);
	for(i=1;i<10;i++)
	{
	     printf("%d ",next[i]);	
	}
	return 0;
}

            结果为

                                     

                                                                           获取next数组的结果图

2,KMP算法的实现

               

//返回子串T在主串S第pos个字符之后的位置 
int Index_KMP(String S,String T,int pos)
{
    int i = pos;
	int j = 1;
	int next[255];
	
	get_next(T,next);
	
	while(i<=S[0]&&J<=T[0])
	{
	     	if(S[i] == T[j])
	     	{
			    i++;
				j++;
				if(T[i]!=T[j])
				{
				     next[i] = j;	
				}		
				else
				{
				     next[i] = next[j];	
				}
			}
			else
			{
			    j = next[j];	
			}
	}
	if(j>T[0])
	{
	    return i - T[0];	
	}	
	else
	{
	   return 0;	
	}
} 


                           

                                  

                                 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值