几种字符串匹配算法[算法学习记录]

字符串匹配是计算机科学中最古老、研究最广泛的问题之一。 ---------百度百科
字符串匹配问题就是说在一个大的字符串中搜索某个字符串的匹配位置。通常我们把那个大的字符串成为母串S,待匹配的那个字符串叫做模式串T。

  • 暴力匹配算法
暴力匹配算法是世界上最容易想到的字符串匹配算法。
int BF(char *s, char *t) {  //s为母串,t为模式串
    int i = 0, j = 0;
    int times = 0;//用来记录匹配字符串过程中的运算次数
    while (s[i]) {
        while (s[i + j] && t[j] && s[i + j] == t[j]) {
            j++;  
            times += 4; 
        }
        if (t[j] == '\0') { //如果模式串匹配结束,输出匹配成功和运算次数
            printf("BF YES : %d\n", times);
            return times;
        }
        times += 3;
        j = 0; 
        i++;
    }
    printf("BF NO : %d\n", times);//当母串被匹配结束,输出匹配失败和运算次数
    return times;
}

暴力匹配算法的过程易于理解,在某些场合下效率也比较高。在匹配成功的前提下,考虑两种极端情况。(主串长n,模式串长m)最好的情况:每次不成功的匹配都发生在模式串第一个字符与主串相应字符比较。平均时间复杂度为O(n+m)。最坏的情况:每次不成功匹配都发生在模式串最后一个字符与主串相应字符的比较,平均时间复杂度为O(n*m)。

  • 著名的看毛片算法(KMP)

kmp算法改进的部分在于每次不匹配时,主串i指针不用回溯。KMP算法最关键的地方就是设法不要将搜索位置移到已经比较过的位置,从而提高效率。到底怎么确定模式串重新和母串比较的位置,这是KMP算法最核心的地方也是最难理解的地方。为此,引出了模式串的next函数。

next匹配表函数

void get_next(char *t, int *next) {
    int j = 1, match = -1; //match为部分匹配值 ,
    next[0] = -1; //将部分匹配值的初始值设为-1
    while (t[j]) {
        while (match != -1 && t[match + 1] != t[j]) {
            match = next[match];
        }
        if (t[match + 1] == t[j]) {
            match++;
        }
        next[j] = match;
        j++;
    }
    return ;
}

KPM算法

void kmp_match(char *s, char *t, int *next) {
    int i = 0, match = -1;
    int times = 0;
    while (s[i]) {
        while (match != -1 && t[match + 1] != s[i]) {
            times += 3;
            match = next[match];
        }
        if (t[match + 1] == s[i]) {
            times += 2;
            match++;
        }
        if (t[match + 1] == '\0') {
            printf("KMP YES : %d\n", times);
            return ;
        }
        times += 2;
        i++;
    }
    printf("KMP NO : %d\n", times);
    return ;
}

‘看毛片’算法不易理解,就像我们刚看‘毛片’的时候找资源时候那么困难[手动滑稽],网上很多博客讲解,可以结合着学习理解,试着实现一下,当我们get到自己的那个点以后就会轻松很多。同样,KPM算法最优时间复杂度为O(m+n),最坏时间复杂度为(m*n),平均为(m+n)。

  • SUNDAY算法

经历了痛苦KPM算法,求next到崩溃。最近学习到一种SUNDAY算法,那叫一个就简单高效~~
SUNDAY算法原理从前往后匹配,如果遇到不匹配情况判断母串S参与匹配的最后一位的下一位字符,如果该字符出现在模板串T中,选择最右出现的位置进 行对齐;否则直接跳过该匹配区域。

翠花,上代码~~

void sunday(char *s, char *t) {
    int str_index[256] = {0};
    int len_t = strlen(t);//模式串长度
    int len_s = strlen(s);//母串长度
    for (int i = 0; i < 256; i++) {
        str_index[i] = len_t + 1;
    }
    for (int i = 0; t[i]; i++) {
        str_index[t[i]] = len_t - i;   //出现在模式串中最有出现的位置和母串对齐
    }
    int i = 0, j = 0;//i,j分别是母串,模式串的下标
    int times = 0;
    while (i + len_t <= len_s) {
        if (s[i + j] != t[j]) {
            times += 3;
            i += str_index[s[i + len_t]];
            j = 0;
        } else {
            times += 2;
            j++;
        }
        if (t[j] == '\0') {
            printf("sunday YES : %d\n", times);
      return ;
        }
    }
    printf("sunday NO : %d\n", times);
    return ;
}

sunday算法简单高效,最优情况下时间复杂度能达到O(n/m),最差情况时间复杂度为O(n*m),平均O(n+m)。

最近还看到一个让人眼前一亮的字符串匹配算法:shift-and算法,有兴趣的可以去搜一下看看,那种感觉就像是打开了新世界的大门。

小结:

--本文介绍了暴力匹配算法,KPM算法,SUNDAY算法三种字符串匹配算法。如果您有任何批评,建议或者补充,请留言指出,不胜感激。更多参考可以移步互联网。

你可能感兴趣的:(几种字符串匹配算法[算法学习记录])