KMP字符串匹配算法

KMP字符串匹配算法

推荐一个讲解视频:B站KMP讲解视频

  KMP整个算法分为三个阶段,如下:
  (1) cal_next_1,计算待匹配字符串的前后缀数组next;
  (2) move_next,next右移一位,next[0] = -1
  (3)进行字符串匹配.
  其中在计算next数组时有两种方法,一个是比较简单的常规方法直接计算next数组,另一种是比较高阶的方法,两种都应该要掌握.

#include 
#include 

using namespace std;

/**
 * 题目:KMP字符串匹配算法
 * 描述:使用KMP算法实现字符串匹配
 * 思路:1.计算next;2,.右移next;3.匹配字符串
 * 备注:掌握KMP
 */

//方法1:计算next数组,采用递推式的方法,效率更高
vector cal_next_1(string needle) {
    int len = needle.length();
    vector next(len, 0);
    next[0] = 0;
    int val = 0;
    int i = 1;
    while (i < len) {
        if (needle[i] == needle[val]) {
            val = val + 1;
            next[i] = val;
            i++;
        } else {
            if (val > 0) {
                val = next[val - 1];      //偏移映射
            } else {
                next[i] = 0;
                i++;
            }
        }
    }
    for (int i = 0; i < next.size(); i++) {
        cout << next[i] << " ";
    }
    cout << endl;
    return next;
}

//方法2:计算next数组,采用普通方法求解,效率较低,但易懂
vector cal_next_2(string needle) {
    int len = needle.length();
    vector next(len, 0);
    for (int i = 0; i < len; i++) {
        string substr = needle.substr(0, i + 1);
        int len_sub = substr.length();
        for (int j = len_sub - 1; j > 0; j--) {
            string sub_front = substr.substr(0, j);
            string sub_last = substr.substr(len_sub - j, j);
//            cout << sub_front << " " << sub_last << endl;
            if (sub_front == sub_last) {
                next[i] = j;
                break;
            }
        }
    }

    for (int i = 0; i < next.size(); i++) {
        cout << next[i] << " ";
    }
    cout << endl;
    return next;
}

//next数组向右移动一位
vector move_next(vector next) {
    int len = next.size();
    for (int i = len - 1; i > 0; i--) {
        next[i] = next[i - 1];
    }
    next[0] = -1;
    return next;
}

//KMP字符串匹配函数
void kmp_search(string haystack, string needle) {
    int len_1 = haystack.length();
    int len_2 = needle.length();

    vector next1 = cal_next_1(needle);     //求next数组(简单版)
    vector next2 = cal_next_2(needle);     //求next数组(增强版)

    vector next = move_next(next1);        //next数组向右移动一位,next[0] = -1;

    //开始匹配
    int i = 0;  //指向 haystack 的下标
    int j = 0;  //指向 needle 的下标
    while (i < len_1) {
        if (j == len_2 - 1 && haystack[i] == needle[j]) {
            cout << "Find at " << i - j << endl;
            j = next[j];                        //继续往后匹配
        }
        if (haystack[i] == needle[j]) {         //匹配正确,j和i同时右移
            i++;
            j++;
        } else {
            j = next[j];                        //匹配错误,j回退到next[j]
            if (j == -1) {                      //如果j=-1,则j和i同时右移
                i++;
                j++;
            }
        }
    }

}

int main() {
    string haystack = "ABABABABCABAABABABCABAAD";
    string needle = "ABABCAB";
    kmp_search(haystack, needle);
    return 0;
}

你可能感兴趣的:(C/C++)