一、BF
从主串S的第pos个字符起和模式串的第一个字符比较之,若相等,则继续比较后续字符;否则从主串的下一个字符起再重新和模式T的字符比较之。依此类推,直至模式T中的每一个字符依次和主串S中的一个连续的字符串序列相等,则称匹配成功,函数值为和模式T中的第一个字符相等的字符在主串S中的下标;否则称匹配不成功,函数值为-1。(下标是从0开始的)。
#include<stdio.h> //printf()
#include<assert.h> //exit() assert()
#include<string.h>
int bf(char *S, char *T, int pos){
assert(S != NULL && T != NULL);
int i = pos;
int j = 0;
while(i < strlen(S) && j < strlen(T)){
if(S[i] == T[j]){
++i;
++j;
}
else
{
i = i - j + 1;
j = 0;
}
}
return j >= strlen(T)? i-j : -1;
}
int main(){
char s[] = {"abcababcabc"};
char t[] = {"abcabc"};
int res;
res = bf(s,t,3);
printf("%d\n", res);
exit(0);
}
二、KMP算法
不谈原理,只谈如何理解和使用。
去掉已经有确切结果的比较。观察图2,S串和P串,在i=5和j=5处失配。按照BF算法的思想,i将回退到i-j+1的位置,j清零。这带来一个问题:S[1] != P[0]故主串移动一字符,重新匹配而S[2]!=P[0](这两处比较是无用的,因为肯定不相等);再重新匹配S[3]=P[0],S[4]=P[1],但是这两个字符相等是可以推导出来的(故这两个字符的比较也是无用的),最理想的比较应该是S[5] ?= P[3]!这一点将在KMP中巧妙实现。
观察图3,6号位置的字符b对应的值为1需要说明:0号位置和5号位置的字符相同,除此之外,就没有了,故而在子串[0...6]中,最长头尾真子串长度为1,将1和6号位置的字符b对应。研究7号位置字符对应的数值的时候,因为6号位置所对应的数值为1,我们就需要判断串中1号位置和6号位置字符是否相等,相等的话,在前面一个字符对应的数值的基础上加1。不相等的情况稍后讨论!
观察图4,此时9号位置字符不等于6号位置字符,需要一直向前回溯,直到到达尽头。故13号位置的字符对应的数值为0。这属于不相等情况中的最后也未找到的情况。
观察图5,最终找到了!!!
#include<string.h> //memset()
#include<stdio.h> //printf()
#include<assert.h> //assert()
#include<malloc.h> //malloc()
void get_next(const char *T, int next[]){
assert(T != NULL);
int n = strlen(T);
int i = 2;
int k = 0; //k = next[i-1] == next[0] == 0;
next[0] = -1;
next[1] = 0;
while(i < n){
while(k > -1 && T[i-1] != T[k]){
k = next[k];
}
next[i++] = ++k;
}
}
int kmp(const char* S, const char* T, int pos){
assert(S != NULL && T != NULL);
int slen = strlen(S);
int tlen = strlen(T);
int i = pos;
int j = 0;
int *next = (int *)malloc(sizeof(int)*tlen);
assert(next != NULL);
memset(next, 0, sizeof(int)*tlen);
while(i < slen && j < tlen){
if(j == -1 || S[i] == T[j]){
i++;
j++;
}
else{
j = next[j];
}
}
free(next);
return j >= tlen ? i-j : -1;
}
代码不多,但是需要逐行去体会!!!