[数据结构复习] 1 - KMP算法及其改进

数据结构复习[1] - KMP算法及其改进

模式匹配

模式匹配就是给定模式串和主串,在主串中找模式串第一次出现的位置的算法。

BF算法

BF算法就是暴力匹配算法,下面给个简单代码就过吧。

char* s1 = "abcaba";//主串
char* s2= "aba";//模式串
int i=0;//主串中的位置
int j=0;//模式串中的位置
while(i<strlen(s1)&&j<strlen(s2)){//防止越界
    if(s1[i]==s2[j]){//匹配成功则比较下一位
        i++;
        j++;
    }else{
        i=i-j+1;//匹配失败,i回退
        j=0;//j从0开始匹配
    }
}
if(j>strlen(s2)){
    cout<<i-j<<endl;//找到了输出位置
}else{
    cout<<-1<<endl;//没找到输出-1
}

KMP算法

上面的暴力算法回退的太多,很多无用的比较,浪费时间,KMP算法解决了这个问题,提出了next数组,使得在一次比较失败之后可以快速跳过无用比较,大大简化了算法。其思路是主串的i每次不回退,j不一定回退到0,而是按照next数组回退到对应的位置,那么关键就是next数组的计算了。


next数组

next数组存在的意义是为了简化j的回退,方便理解而言,提出了最长公共前后缀的概念,但实际代码中并不体现这种理解。

例如,对于字符串“abcsab”的前缀串集合为{a,ab,abc,abcs,abcsa},后缀串集合为{b,ab,sab,csab,bcsab},可以看出最大公共前后缀字串为ab。长度为2,因此对应next数组值就是2。

求解代码:

void get_next(char* s,int* next){
    next[0] = -1;
    next[1] = 0;
    int k = 0;//初始位置next值
    int i = 2;//初始需要赋值的位置
    while(i<strlen(s)){
        if(k==-1||s[i-1]==s[k]){//如果相等,next的值就是当前位置next的值+1
            next[i++] = ++k;
        }else{
            k = next[k];//不相等则继续往前找,直到k=-1或者找到相等的
        }
    }
}

模式匹配代码:

int KMP(char* m,char* s,int pos){//pos是指从pos位置开始匹配
    int i=pos;
    int j=0;
    int* next = new int[strlen(s)];
    get_next(s,next);
    while(i<strlen(m) && j<strlen(s)){
        if(j==-1 || m[i]==s[j]){
            j++;
            i++;
        }else{
            j = next[j];//直接按照next数组进行回退
        }
    }
    delete next;
    if(j>=strlen(s)){
        return i-j;
    }else{
        return -1;
    }
}

改进的KMP算法

上面的KMP算法存在的问题是,如果模式串为"aaaaaaaab",那么其next数组的值便是[-1,0,1,2,3,4,5,6,7],也就意味着,如果最后一个a不匹配,那么将一步一步回退j,回退了之后进行重复的比较,继续回退(因为还是a,还是失配)。所以我们如果能判断s[i]是否与s[k]相等,如果相等,其next值直接为next[k]就好了。所以改进后的next数组值应该为[-1,-1,-1,-1,-1,-1,-1,-1,0]

改进的next求解代码

int* get_next_plus(char* s,int* next){
    next[0] = -1;
    int i=0;
    int k=-1;
    while(i<strlen(s)){
        if(k==-1 || s[i]==s[k]){
            i++;
            k++;
            if(i>=strlen(s)){
                break;
            }
            if(s[i]==s[k]){
                next[i] = next[k];
            }else{
                next[i] = k;
            }
        }else{
            k = next[k];
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/aoru45/p/10429897.html