子串查找之KMP算法

KMP算法

首先先简单讲述BF算法:该算法通过子串的字符与主串的字符一个一个匹配,若序列一次性完全匹配,则返回在主串中的位置,若不匹配则子串下标重置为0,主串下标+1,可见效率低下,例如当主串为aaaaabbbbb,子串为aaaab,子串的前四个字符与主串前五个字符完全相同,到进行到下标等于5时不匹配需要将子串下标置0,主串下标0+1,依次循环重复。

BF代码:

int strstr(char *s1, const char *s2)
{
	int ps1 = 0;//主串下标
	int ps2 = 0;//子串下标
	int len = 0;
	int ret = 0;
	len = (int)strlen(s2);
	while(s1[ps1] != 0){
		if(s1[ps1] != s2[ps2]){
			ps2 = 0;
			ps1 = 0;
			s1++;
			ret++;
		}
		else if(s1[ps1] == s2[ps2]){
			ps1++;
			ps2++;
		}
		if(ps2 == len){
			break;
		}
	}
	return ret;
}

KMP算法:代码中有详细讲述,包括测试程序。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct kmp_str{
	int length;
	char *array;
	int *next;
}string,*p_string;

p_string get_kmp_str(char *a)
{
	int i,j;
	//初始化KMP结构体
	p_string T = (p_string)malloc(sizeof(string));
	T->length = (int)strlen(a);
	T->array = (char *)calloc(sizeof(char), T->length + 1);
	strncpy(T->array, " ", 2);
	strncat(T->array, a, T->length + 1);
	T->next = (int *)calloc(sizeof(int), T->length + 1);
	//获取next数组
	i=1;//后缀
	j=0;//前缀
	T->next[1]=0;
	//前后缀的作用,前缀从0开始与后缀进行依次比较,获取重复的序列,前缀用来指明当前后缀指向的元素前有最大重复的序列长度+1,next保存每一个元素位置前的最大重复的序列长度+1。
	while( i < T->length )
	{
		if( 0==j || T->array[i] == T->array[j] )
		{
			i++;
			j++;
			//如果后元素与前元素相等,则next执行前元素的next。不相等则next指向j前缀。避免后元素匹配不成功后,next指向的前元素本身与后元素相等,导致效率低下
			if( T->array[i] != T->array[j] )
			{
				T->next[i] = j;
			}
			else
			{
				T->next[i] = T->next[j];
			}
		}
		else
		{
			j = T->next[j];//前缀固定而后缀时固定的
		}
	}
	return T;
}

int search(char *S, p_string T)
{
	int ps = 0;
	int pt = 1;

	while(S[ps] != 0){
		if(S[ps] == T->array[pt]){
			ps++;
			pt++;
			if(pt > T->length)
				return ps - pt + 1;
		}else
			pt = T->next[pt];
		if(pt == 0){
			ps++;
			pt++;
		}
	}
	return -1;
}

int main()
{
	int pos = 0;
	char a[] = "wangkaijiaaiyehuiling";
	char b[128] = {0};
	printf("主串为:%s\n",a);
	printf("请输入要查找的子串:");
	scanf("%s",b);
	p_string T = NULL;
	T = get_kmp_str(b);
	pos = search(a, T);
	if(pos > 0)
		printf("成功匹配子串:%s,位于%d\n", b, pos);
	else
		printf("主串:%s中无:%s!\n",a,b);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值