序列比對(26)精準匹配之KMP演算法、Trie樹以及AC自動機
- 2019 年 10 月 8 日
- 筆記
前文已經介紹過KMP演算法和Trie樹,本文將在此基礎上介紹AC自動機。
之前的序列比對文章大都在利用動態規劃演算法解決字元串的非精準匹配
(允許錯配、插入和缺失),比如全局比對和局部比對問題。當然,後來我們還介紹了模序發現和中間字元串問題,並初次學習了如何用分支定界法解決這一類問題。
既然有非精準匹配問題,就有精準匹配
問題。所謂精準匹配,就是兩個字元串在比對時,不允許錯配、插入和缺失。其實,筆者之前已經有過介紹:
KMP演算法
《演算法(四)(轉載)KMP演算法》一文介紹了KMP演算法
,該演算法常用來解決如何在一個長字元串(模板串)中尋找一個短字元串(模式串)的問題。其特點就是要預先對模式串進行處理,對其構建一個next數組
,該數組中存放著模式串每一個位置所對應的跳轉指針,這樣做的效果是模板串的指針不用回溯,一直在遞增,從而增加效率。
KMP演算法的完整程式碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLEN 1000 void getNext(const char *pat, int *next, const int n) { /* assume n >= 2 */ int i, j; for (next[0] = -1, next[1] = 0, i = 1, j = 0; i < n - 1;) { while (j != -1 && pat[i] != pat[j]) j = next[j]; next[++i] = ++j; } } int KMP(const char *temp, const int m, const char *pat, const int n) { int i, j; int *next = (int*) malloc(sizeof(int) * n); getNext(pat, next, n); for (i = 0, j = 0; i < m && j < n;) { if (j == -1 || temp[i] == pat[j]) { i++; j++; } else { j = next[j]; } } free(next); if (j < n) return -1; return i - j; } int main(void) { char t[MAXLEN], p[MAXLEN]; int index; printf("the temp str: "); scanf("%s", t); printf("the pattern str: "); scanf("%s", p); if ((index = KMP(t, strlen(t), p, strlen(p))) == -1) printf("Not found!n"); else printf("Index is %d.n", index); return 0; }
其效果如下:

Trie樹(字典樹)
《演算法(五)字典樹演算法快速查找單詞前綴》一文介紹了Trie樹
,該演算法常用來解決如何在多個模板串中尋找一個模式串的問題。其特點就是將多個模板串裝填進一個樹結構中,雖然使用了較多的空間,但是查找效率得到了提升。
Trie樹的完整程式碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 26 #define MAXLEN 1000 struct Node { struct Node *a[N]; int is_end; }; typedef struct Node *tnode; tnode init() { tnode p; int i; if ((p = (tnode) malloc(sizeof(struct Node))) == NULL) { fputs("Error: out of space!n", stderr); exit(1); } for (i = 0; i < N; i++) p->a[i] = NULL; p->is_end = 0; return p; } void delete(tnode p) { int i; for (i = 0; i < N; i++) if (p->a[i] != NULL) delete(p->a[i]); free(p); } void insert(const char *s, tnode p) { int i; while (*s != 'n' && *s != '