KMP子串匹配(只能匹配出唯一子串)

using namespace std;
#include <iostream>
#include<string>

//自定义字符串存储结构String(包括char数组、length长度)
#define maxlen 20
typedef struct {  
    char ch[maxlen];
    int length;
}String;

//初始化s
void strInit(String& s) {
    s.length = 0;
    s.ch[0] = s.length; //ch[0]空着用来存长度,初始化为0
}

//s判空
bool strEmpty(String s) {
    if (s.length == 0) //如果长度为0代表空串
        return true;
    else
        return false;
}

//获得s长度
int strLength(String s) {
    cout << "长度打印:" << s.length << endl;;
    return s.length; //或者s.ch[0]
}

//将string字符串赋值到s数据结构中用char数组保存
String strAssign(String &s, string t) {
    int i = 1; //从1开始存字符,0空着用来存长度
    s.length =0;
    cout << "字符串打印:";
    for (int j = 0; j < t.length(); j++) {
        s.ch[i] = t[j];
        cout << s.ch[i] << " ";
        s.length++;
        i++;
    }
    s.ch[0] = s.length; //0空着用来存长度
    cout << endl;
    return s;
}

/////////上面都是一些基础函数,下面开始KMP算法/////////////////////////////////////////////
//step1:求出子串的next[j]值【普通版】
void get_next(String s, int next[]) {
    int j = 1, k = 0;
    next[1] = 0; //next[1]值必须填0
    while(j<s.length){
        if (s.ch[j] == s.ch[k] || k == 0) {
            j++;
            k++;
            next[j] = k;
        }
        else
            k = next[k];
    }
    //打印看看
    cout <<"打印next[i]为: ";
    for (int i = 1; i <=s.length; i++)
        cout << next[i] << " ";
    cout << endl;
}

//step1:求出子串的nextval[j]值【改进版,只记录不相同值的索引,避免j的无效回退。2个方法2选1即可】
void get_nextval(String s, int nextval[]) {
    int j = 1, k = 0;
    nextval[1] = 0; //nextval[1]值必须填0
    while (j < s.length) {
        if (s.ch[j] == s.ch[k] || k == 0) {
            j++;
            k++;
            if (s.ch[j] != s.ch[k])
                nextval[j] = k;
            else
                nextval[j] = nextval[k];
        }
        else
            k = nextval[k];
    }
    //打印看看
    cout << "打印nextval[i]为: ";
    for (int i = 1; i <= s.length; i++)
        cout << nextval[i] << " ";
    cout << endl;
}

//step2:开始主串中匹配子串,并返回第一个元素出现的位置
int index3(String s, String t, int next[]) {
    int i = 1, j = 1;
    while (i <= s.length && j <= t.length) { //找到最后一个字符为止
        if (j == 0||s.ch[i] == t.ch[j]) { //如果字符不相同或者j为0了,i和j同步往后移1位
            i++;
            j++;
        }
        else
            j = next[j]; //j回退到next[j]位置
    }//while结束,s和t至少有一个找到头了
    if (j > t.length) {
        //打印看看
        cout << "index3打印子串为: ";
        for (int m = i - t.length; m < i; m++)
            cout << s.ch[m] << " ";
        cout << endl;
        return (i - t.length); //或者i-t.length,返回i最开始的位置
    }
    else
        return 0;
}

void main() {
    int next[20];
  int nextval[20];
  string sf = "aaaacabcaaaabab";
  string sz = "aaaab";

    String ss ,tt;
    strInit(ss); //初始化主串
    strInit(tt); //初始化子串
    strAssign(ss, sf);  //把字符串放进数据结构
    strAssign(tt, sz);  //把字符串放进数据结构
    strLength(ss); //获取长度
    strLength(tt); //获取长度

    get_next(tt, next); //获得子串各个next值
    cout << "用next的index3 i下标:" << index3(ss, tt, next) << endl;
    
    get_nextval(tt, nextval); //获得子串各个nextval值
    cout << "用nextval的index3 i下标:" << index3(ss, tt, nextval) << endl;
}

 

KMP子串匹配(只能匹配出唯一子串)

上一篇:ArrayList不安全的实例及解决方案


下一篇:回文子序列