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;
}