KMP搜索算法

**

我终于会了KMP算法了;

**
先创建两个文本zichuan和zhuchuan才能用,这个代码是从文本中读取字符再在文本中搜索的;

Kmp分为两块 1.编码 2.查找

一、编码

1.第一个字符编为-1(便于后边第一个字符比较时不会死循环)
2.之后编码 与第一个字符相同的 编为0之后字符按1 2 3……排,直到再次遇到与第一个字符相同的字符;然后才从0开始编码;
例:
ababc -1 0 0 1 2
abaabcac -1 0 0 0 1 2 0 1

代码

void bianhao()
{
	//printf("%d",zi.zong);
	printf("\n");
	int i,j=0,x=0,y;
	zi.shu[0]=-1;
	for(i=1;i<zi.zong;i++)
	{
		if(zi.str[i]==zi.str[0])
		{
			x=0;
			zi.shu[i]=x;
			x++;	
		}
		if(zi.str[i]!=zi.str[0])
		{
			if(x==0)
			{
				zi.shu[i]=x;
			}
			else
			{
				zi.shu[i]=x;
				x++;
			}
		}
	}	
}

二、查找

需要注意的是,像ababc 这种的子串,当匹配主串时,若前面两个字符ab中有不相同的,则后面的ab可能相同所以编码时需要让子串指向a,让后面进行比较。
在这里插入图片描述
当i和j相同时,i和j统一都向后移动一位。
在这里插入图片描述
当i和j不相同时,将子串移动即j指向的数移动。移动位数等于j-2(即代码中的j-zi.shu[j]),j当前为4,所以需要移动两位。
在这里插入图片描述
此时,i和j仍不相同,则继续移动,j-0即移动2位。
在这里插入图片描述
此时i和j仍不相同,但此时j=0,则i++,
在这里插入图片描述
在这里插入图片描述
此时重复上边操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此时成功匹配;

void bijiao()
{
	int i=0,j=0,x=0,y;
	printf("主串%d\n子串%d\n",zhushu,zi.zong);
	while(j<zi.zong-1&&i<zhushu)
	{
		if(zi.str[j]==stri[i])
		{
			i++;
			j++;
		}
		if(zi.str[j]!=stri[i])
		{
			if(j!=0)
				j=j-(j-zi.shu[j]);
			if(j==0)
				i++;
		}
		//printf("i的值%d j的值%d\n",i,j);
		if(j>=zi.zong)
			break;
	}
	if(j==zi.zong-1)
	printf("\n相同的位置%d\n ",i-zi.zong+2);
	else
	printf("\n没找到!!\n"); 
	
}

完整代码:

 #include<stdio.h> 
#include<stdlib.h>
typedef struct zichuan
{
	char str[50];//修改子串长度zi.str 和zi.shu 都需改动 
	int  shu[50];
	int zong;
}zichuan;
zichuan zi;
char stri[10000000];//主串长度 修改处 
int zhushu;
void shuru();
void shuchu();
void bianhao();
void bijiao();
int  main()
{
	 
	shuru();
	bianhao();
	bijiao();
	shuchu();
	
}

void shuru()
{
	FILE *fp,*fq;
	int h,e;
	if((fp = fopen("zichuan.txt","r")) == NULL)//输入子串字符 
	{
		printf("can not open this file \n");
		exit(0);
	}
	h=ftell(fp);
	fseek(fp,0,2);
	e=ftell(fp);
	fseek(fp,0,0);
	
	zi.zong=e;
	
	while(e-h>0)
	{
		//printf("%d %d ",h,e);
		fscanf(fp,"%c",&zi.str[h]);//一个回车 三个字符去存它   会使字符数组增加三个 
		h++;
	}
		
	fclose(fp);
	
	if((fq = fopen("zhuchuan.txt","r")) == NULL)//输入主串字符 
	{
		printf("can not open this file \n");
		exit(0);
	}
	
	h=ftell(fq);
	fseek(fq,0,2);
	e=ftell(fq);
	fseek(fq,0,0);
	//printf(" h=%d\n ",h);
	zhushu=e-h;
	while(e-h>0)
	{
		
		fscanf(fq,"%c",&stri[h]);
	//	printf("%c ",stri[h]);
		h++;
	}
		
	fclose(fq);
}

void shuchu()
{
	int i=0;
	
	while(i<zi.zong)
	{
		printf("%d",zi.shu[i]);
		i++;
	}
	
}

void bianhao()
{
	//printf("%d",zi.zong);
	printf("\n");
	int i,j=0,x=0,y;
	zi.shu[0]=-1;
	for(i=1;i<zi.zong;i++)
	{
		if(zi.str[i]==zi.str[0])
		{
			x=0;
			zi.shu[i]=x;
			x++;	
		}
		if(zi.str[i]!=zi.str[0])
		{
			if(x==0)
			{
				zi.shu[i]=x;
			}
			else
			{
				zi.shu[i]=x;
				x++;
			}
		}
	}	
}

void bijiao()
{
	int i=0,j=0,x=0,y;
	printf("主串%d\n子串%d\n",zhushu,zi.zong);
	while(j<zi.zong-1&&i<zhushu)
	{
		if(zi.str[j]==stri[i])
		{
			i++;
			j++;
		}
		if(zi.str[j]!=stri[i])
		{
			if(j!=0)
				j=j-(j-zi.shu[j]);
			if(j==0)
				i++;
		}
		//printf("i的值%d j的值%d\n",i,j);
		if(j>=zi.zong)
			break;
	}
	if(j==zi.zong-1)
	printf("\n相同的位置%d\n ",i-zi.zong+2);
	else
	printf("\n没找到!!\n"); 
	
}


// aaba  -1 0 1 2  第一个记为-1是为了好算 只找与第一个字母相同的就成 记为0 之后的数按1 2 3……排 直到再次遇见第一个字母 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值