Kmp算法,c语言实现教你如何从入门到熟练

曾经我要山川大海,要奔腾的青春,开玩笑的,老板,来二两白粥。

公主请收藏!!!

希望大家都能如愿哦!!!

兄弟们,这是我的第一篇博客。

这下面是我对kmp算法的一些看法:

首先我们要定义一个结构体:

定义一个结构体类型:Sqstring,typedef给变量起别名

typedef struct
{
	char data[Maxsize];
	int length;
}Sqstring;


创建一个next[]数组,并获取它的值next[j]==k,在每一次比较子串时,都不包括它本身不匹配处的值。只比较模式串前面的子串有多少个相同的前后缀,就是t[0]...t[k-1]=t[k+1]...t[n].。k记录最大公共子串的数值。

比如:s[i]!=t[m],则比较的是m-1前面的子串并求最大公共子串k,不包括t[m],并把k的值记录到next[j]中。

不加入子串寻找最大公共子串行列。

求next[]数组,就是求最长公共前后缀的长度,只不过用一个数组存放最长前后缀长度罢了,计算最长前后缀,不包括不匹配位置的值,只是匹配:不相等t【m】处前面的值,求最长公共子串,求得后用next[]数组存放这些值,方便不匹配出现时不用回到j=0处重新开始,而是只回到j=next【k】处开始往下匹配。

//定义一个函数,用于获取next[]数组
void GetNext(Sqstring t,int next[])//创建一个Sqstring类型的变量t,在函数形参部分定义,也可以在函数外定义Sqstring t
{
int j,k;
j=0;         //为next[]的的下标,从0开始
k=-1;       //令k=-1;这是约定好的,k为next[]的值,非下标,k记录有几个相同的子串,
           //其实就是开始 ,k=next[0]=-1;
next[0]=-1;//规定好的
while(j<t.length-1)//循环条件,j下标小于t.length的长度;t.length的值是先定义好的,j从0开始
{
if(k==-1||t.data[j]==t.data[k])//先执行k==-1进来
{
j++;
k++;
next[j]=k;   //记录下next[j]的值,相当于输入循环输入next[j]的值,循环条件是j<t.length
         //next[j]数组的值会随着循环改变,
         //j++让其改变位置,k++改变数组的值。
}
else
k=next[k];//k的值在变,变为next[k]上的值,这时候k回退,但是next[k]处的值不变
}
}

kmp函数:核心的点:就是一个下标的回退,下标回退到哪呢,j回退到next[k]=-1,0,1,2.....的位置,就是让j不用回到0重新开始,从j=next[k]重新开始。

int kmp(Sqstring s,Sqstring t)//输入主串s,输入子串t的值
{
int next[Maxsixe],i=0,j=0;
GetNext(t,next);//获取next[]数组的值


while(i<s.length&&j<t.length)
{
if(j==-1||s.data[j]==t.data[j])//条件判断
{
i++;
j++;
}
else
   j=next[j];//i不变,j回退到next[j]的位置,本质来说就是此时j取next[j]的值,j回退到next[j]的值
             //j从next[j]的值重新开始循环,i从i开始,i不变,这时s[i]和t[j]处不匹配,j重新赋值next[j]的值
}             //这时候,模式串t的位置就是t[next[j]]的位置,相对于主串s往右移动。



if(j>=t.length)      //如果匹配成功,就返回子串的位置,头位置t.length
    return(i-t.length);

else           //匹配不成功,返回-1
return -1;//


}

改良后的版本nextval数组

void GetNextval(Sqstring t,int nextval[])
{
int j=0;
int k=-1;
nextval[0]=-1;

while(j<t.length-1)
{  if(k==-1||t.data[j]==t.data[k])
   
   {
     j++;
     k++;
     if(t.data[j]!=t.data[k])
         nextval[j]=k;
     else
         nextval[j]=nextval[k];
   }
else
     k=nextval[k];
   }

}



改良后的kmp算法,时间复杂度是O(n+m)

int KMP(Sqstring s,Sqstring t)
{
int nextval[Maxsize],i=0,j=0;
GetNextval(t,nextval);
while(i<s.length&&j<t.length)
{
if(j==-1||s.data[i]==t.data[j])
{
i++;
j++;
}
else
     j=nextval[j];
}

if(j>=t.length)
    return (i-t.length);
else

   return((-1)
}

总代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Maxsize  50
typedef struct
{
	char data[Maxsize];
	int length;
}Sqstring;



void GetNext(Sqstring t,int next[])
{
	int j,k;
	j=0;
	k=-1;
	next[0]=-1;
	while(j<t.length-1)//求t所有位置的next值
	{
		if(k==-1||t.data[j]==t.data[k])
		{
			j++;k++;
			next[j]=k;
		}
		else
			k=next[k];//k回退,令k等于next[k]位置的值;如:next[k]=2;
		//再执行循环;一直循环,直到找到k=-1或者t.data[j]=t.data[k];


	}
}


int kmp(Sqstring s,Sqstring t)
{
	int next[Maxsize],i=0,j=0;
	GetNext(t,next);
	while(i<s.length&&j<t.length)
	{
		if(j==-1||s.data[i]==t.data[j])
		{
			i++;
			j++;
		}
		else
			j=next[j];//记得是j的位置,不是记录next[j]的值,你不要搞错了
	}                  //让j=next[j]的值,从GetNext中获得next[]数组,不要担心越界,因为while 
                         严格控制j的长度。
	                    //i不变,j回退。


	if(j>=t.length)//匹配成功
		return i-t.length;//返回子串的位置头位置
	else//匹配不成功,返回-1
		return (-1);
}

int main()
{
	Sqstring s={{"djjjkssdksbibfjnakm"},40};
	Sqstring t={{"ssdk"},4};//4代表长度,t.length,超过长度就不行,因为超过的长度就是一个随机 
                              数,根本查不到
	int next[Maxsize];
	GetNext(t,next);
	for(int i=0;t.data[i]!='\0';i++)//判断条件只是针对字符串,可以用i<t.length

{
		printf("next[%2d]=%2d\n",i,next[i]);
	}
	printf("return =%d\n",kmp(s,t));
	system("pause");
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值