两种常见的模式匹配算法(代码实现)

BF算法(暴力法)

不多解释,直接上代码:

// BF算法 O(mn)
int bf(SString s, SString t, int pos){
    int i = pos, j = 0;
    while (i < s.length && j < t.length){
        if (s.ch[i] == t.ch[j]){
            i++;
            j++;
        } else {
            i = i - j + 1;
            j = 0;
        }
    }
    if (j >= t.length) 
        return i - t.length;
    else 
        return -1;
} 

// 另一个版本的BF算法 - O(mn) 
int pm(SString s, SString t, int pos){
    for (int i = pos; i <= s.length-t.length; i++){
        bool status = true;
        for (int j = 0; j < t.length; j++){
            if (s.ch[i+j] != t.ch[j]){
                status = false;
                break;
            }
        }
        if (status)
            return i;
    }
    return -1;
} 

KMP算法

KMP算法较难理解,在大二上数据结构这门课的时候就没有搞懂,今天花了点时间终于把它看懂了。

KMP算法相比BF算法,其改进主要在使用了一个前后缀匹配数组next(我自己起的名儿~)来记录前缀和后缀的匹配信息,以使得在发现主串与模式串的比较中出现不匹配时,主串指针无需回溯,并根据前后缀匹配数组中的信息,向后移动,从而减少了多余的比较。

代码实现:

// KMP算法
int kmp(SString &s, SString &t, int pos){
    int next[t.length], j = 0, i = 0;
    get_next(t, next);
    
    while (i < s.length && j < t.length){
        if (j == -1 || s.ch[i] == t.ch[j]){
            i++; j++;
        } else 
            j = next[j];
    }
    if (j >= t.length)
        return i-t.length;
    else 
        return -1;
}


void get_next(SString &t, int next[]){
    int i = 0, j = -1;
    next[0] = -1;
    while (i < t.length - 1){
        if (j == -1 || t.ch[i] == t.ch[j]){
            i++; j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
} 

参考博客:

可运行的整体代码:

#include<iostream>
#define MAXLEN 100
#define CHUNKSIZE 50

using namespace std;

// 串的普通顺序存储
typedef struct {
    char ch[MAXLEN+1];
    int length;
}SString; 

// 串的堆式顺序存储 
//typedef struct {
//    char *ch;
//    int length;
//}SString;

// 串的链式存储
typedef struct chunk{
    char ch[CHUNKSIZE];
    struct chunk *next;
}Chunk;

typedef struct {
    Chunk *head, *tail;
    int length;
}LString; 

// 普通顺序存储的初始化操作 
void SsInit(SString &s){
    s.length = 0;
}

void SsInput(SString &s){
    char c;
    while ((c = getchar()) != '
'){
        s.ch[s.length++] = c;
    }
}

void printString(SString &s){
    for (int i = 0; i < s.length; i++){
        cout << s.ch[i];
    }
    cout << endl;
} 

// BF算法 - O(mn) 
int pm(SString s, SString t, int pos){
    for (int i = pos; i <= s.length-t.length; i++){
        bool status = true;
        for (int j = 0; j < t.length; j++){
            if (s.ch[i+j] != t.ch[j]){
                status = false;
                break;
            }
        }
        if (status)
            return i;
    }
    return -1;
} 

// 另一种版本的BF算法 O(mn) - 与暴力法相似 
int bf(SString s, SString t, int pos){
    int i = pos, j = 0;
    while (i < s.length && j < t.length){
        if (s.ch[i] == t.ch[j]){
            i++;
            j++;
        } else {
            i = i - j + 1;
            j = 0;
        }
    }
    if (j >= t.length) 
        return i - t.length;
    else 
        return -1;
} 

// KMP算法
int kmp(SString &s, SString &t, int pos){
    int next[t.length], j = 0, i = 0;
    get_next(t, next);
    
    while (i < s.length && j < t.length){
        if (j == -1 || s.ch[i] == t.ch[j]){
            i++; j++;
        } else 
            j = next[j];
    }
    if (j >= t.length)
        return i-t.length;
    else 
        return -1;
}


void get_next(SString &t, int next[]){
    int i = 0, j = -1;
    next[0] = -1;
    while (i < t.length - 1){
        if (j == -1 || t.ch[i] == t.ch[j]){
            i++; j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
} 

 
int main(){
    SString s, t;
    SsInit(s);
    SsInput(s);
    SsInit(t);
    SsInput(t);
    
    int loc = -1; 
//    loc = pm(s, t, 0);
//    loc = bf(s, t, 0);
    loc = kmp(s, t, 0);
    
    cout << loc << endl;
}


CS专业在读,热爱编程。
专业之外,喜欢阅读,尤爱哲学、金庸、马尔克斯。
原文地址:https://www.cnblogs.com/jmhwsrr/p/14544704.html