序列比对(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 != '