KMP算法C语言

KMP算法是一种改进的字符匹配算法,具体实现是通过构造
next数组,通过next数组指示下一轮应用于进行匹配的元素位置

减少了模式串与主串的匹配次数,优化了算法的时间复杂度。
S串 主串

T串 模式匹配串
next数组的建立原理

建立一个字符串数组,字符串数组的第一个元素a[0]规定用存放
数组中含有的字符个数。

比如主串S为abaabaaab,则s[0] = 9,s[1] = 'a',s[2] = 'b',s[3] = 'a';

对于模式匹配串T为baaa,通过建立关于他的next数组可以指导模式匹配串
与主串失配时下一轮进行的字符匹配。

每个元素对应位置的next元素由其前面的字符串中,前缀和后缀匹配的个数决定
如T[1]对应的next数组元素next[1] = 0,应为他前面没有任何元素,0代表下一
轮匹配将由T[0]匹配当前主串元素。对于T[2] = a,它对应的next数组元素为1,应
为他前面没有任何前缀和后缀相匹配,前缀为b,后缀为a,所以失配时应该将T[1]

位置元素对准当前主串元素。
C语言构造next数组
void next_array(char *a,int *b)  //构造next数组 
{
    int i,j;
    b[0] = -1;
    b[1] = 0;
    i = 0;
    j = 1;
    while(j < a[0])
    {
    	if(i == 0||a[i] == a[j])
    	{
    		i++;
    		j++;
    		b[j] = i;
		}
		else
		  i = b[i];
	}
    
}

数组a为字符串数组,b为next数组next[0]不对应任何位置所以用-1代替。
用i和j两个游标分别代表前缀,和后缀,i的数值上等于前缀和后缀匹配的个数

,当前缀和后缀出现不匹配时,i回溯到b[i],应为b数组即next数组指导模式匹配串失配时
下一轮应该匹配的位置。

KMP算法主体

void kmp(char s[],char t[],int c[])  //kmp主体
{
	int i,j,m;
	int next[255];        //t串next数组
	i = 1;
	j = 1;
	m = 0;
	next_array(t,next);   //构造next数组
	while(i <=s[0])
	{
		if(s[i] == t[j] || j == 0)      //匹配字符串
		   {
		   	  i++;
		   	  j++;
		   	 if(j == t[0]+1)
		   	 {
		   	 	 j = 1;
		   	 	 c[m] = i - t[0];
		   	 	 m++;
				}
		   }
		   else
		    j = next[j];
	}
}

游标i,j分别匹配主串,模式匹配串,如果匹配完成,则j重置
为1直到主串走完。将位置存入数组中。

完整代码

#include<stdio.h>
#include<malloc.h>

void create(char s[])   //创建字符串
{
	int i;
	printf("number of chars:\n");
	scanf("%d",&s[0]);
	getchar();
	printf("enter chars:\n");
	for(i = 1; i < s[0] + 1;i++)
	{
		scanf("%c",&s[i]);
	}
	getchar();
	printf("\n");
	
}

void show_array(char s[])     //输出字符串
{
      int i = 1;
      printf("%d ",s[0]);
      for(;i<s[0] + 1;i++)
      {
      	printf("%c ",s[i]);
      	
	  }
	  printf("\n\n");
}

void next_array(char *a,int *b)  //构造next数组 
{
    int i,j;
    b[0] = -1;
    b[1] = 0;
    i = 0;
    j = 1;
    while(j < a[0])
    {
    	if(i == 0||a[i] == a[j])
    	{
    		i++;
    		j++;
    		b[j] = i;
		}
		else
		  i = b[i];
	}
    
}

void kmp(char s[],char t[],int c[])  //kmp主体
{
	int i,j,m;
	int next[255];        //t串next数组
	i = 1;
	j = 1;
	m = 0;
	next_array(t,next);   //构造next数组
	while(i <=s[0])
	{
		if(s[i] == t[j] || j == 0)      //匹配字符串
		   {
		   	  i++;
		   	  j++;
		   	 if(j == t[0]+1)
		   	 {
		   	 	 j = 1;
		   	 	 c[m] = i - t[0];
		   	 	 m++;
				}
		   }
		   else
		    j = next[j];
	}
}

int main()
{
	char a[255];   //s串
	int i;
	int next[255];  //s串next数组
	int c[255];     //存放多个匹配串位置
	char t[255];   //t串
	c[0] = 0;   //标记是否有匹配串
	printf("\n");
	while(1){
	printf("array S\n");
	create(a);            //创建s串
	printf("array T\n");
	create(t);           //创建t串
	printf("char array S\n\n");
    show_array(a);             
	printf("char array T\n\n");
	show_array(t);
	printf("next array\n\n");
	next_array(t,next);      
   for(i = 0;i<t[0]+1;i++)        //显示t串next数组
        printf("%d ",next[i]);
   printf("\n\n");
   kmp(a,t,c);        //KMP
   printf("KMP");
   printf("\n\n");
   i = 0;
   if(c[i] == 0)    //如果没有则错误
   printf("error!");
   else
   while(c[i] != 0&&c[i] <= a[0])   //否则顺序输出所有匹配串位置
   {
   	
   	printf("%d ",c[i]);
   	i++;
   }
   printf("\n\n");
}
   
	return 0;
}

create函数创建字符串,show_array函数打印字符串。
演示效果 编译器DEV C++

猜你喜欢

转载自blog.csdn.net/jazrynwong/article/details/80546250