**
我终于会了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……排 直到再次遇见第一个字母