小菜鸟 菜谈 KMP->字典树->AC自动机->trie 图 (改进与不改进)

本文的主要宗旨是总结自己看了大佬们对AC自动机trie 图 的一些理解与看法。(前沿:本人水平有限,总结有误,希望大佬们可以指出)

KMP分割线-------------------------------------------------------------------------------------------------------------------------------------

引入:https://www.cnblogs.com/zhangtianq/p/5839909.html(KMP全面解释)

总结:KMP对于 单模匹配通过 next数组 去到失配该到的地方,复杂度达到(O(n))

字典树-----------------------------------------------------------------------------------------------------------------------------------------

引入:https://blog.csdn.net/weixin_39778570/article/details/81990417

一, 原理图

Trie树包含的字符串集合是{in, inn, int, tea, ten, to}

字典树又称为前缀树 ,我们很明显的可以的观察到从根节点到标记节点(黑色),都在字符串集合,反之不在: 例如 0->1->2  = in 

二, 构造过程

假设我们要插入字符串”in”。我们一开始位于根,也就是0号节点,我们用P=0表示。我们先看P是不是有一条标识着i的连向子节点的边。没有这条边,于是我们就新建一个节点,也就是1号节点,然后把1号节点设置为P也就是0号节点的子节点,并且将边标识为i。最后我们移动到1号节点,也就是令P=1。

这样我们就把”in”的i字符插入到Trie中了。然后我们再插入字符n,也是先找P也就是1号节点有没有标记为n的边。还是没有,于是再新建一个节点2,设置为P也就是1号节点的子节点,并且把边标识为n。最后再移动到P=2。这样我们就把n也插入了。由于n是”in”的最后一个字符,所以我们还需要将P=2这个节点标记为终结点

现在我们再插入字符串”inn”。过程也是一样的,从P=0开始找标识为i的边,这次找到1号节点。于是我们就不用创建新节点了,直接移动到1号节点,也就是令P=1。再插入字符n,也是有2号节点存在,所以移动到2号节点,P=2。最后再插入字符n这时P没有标识为n的边了,所以新建3号节点作为2号节点的子节点,边标识为n,同时将3号节点标记为终结点:

总的来说,对于目前想要插入字符串 W , 从根节点判断有无连线的 W[0] 的边,有就往下走到节点P,判断节点P有无连 W[1]的边,没有就新建一个节点X表示 P链接W[1] 后到达X;

三,怎么使用

如何查询Trie树中是不是包含字符串S,也就是之前提到的查找操作。查找其实比较简单。我们只要从根节点开始,沿着标识着S[1] -> S[2] -> S[3] … -> S[S.len]的边移动,如果最后成功到达一个终结点,就说明S在Trie树中;如果最后无路可走,或者到达一个不是终结点的节点,就说明S不在Trie树中。
例如:如果是查找”te”,就会从0开始经过5最后到达6。但是6不是终结点,所以te没在Trie树中。如果查找的是”too”,就会从0开始经过5和9,然后发现之后无路可走:9号节点没有标记为o的边连出去。所以too也不在Trie中。

四,盗取模板,嘻嘻

#include<string.h>
#include<stdio.h>
#include<malloc.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 26 + 1;

struct Trie
{
    int Next[maxn], v;
    inline void init(){
        v = 1;
        memset(Next, -1, sizeof(Next));
    }
};

struct Trie Node[1000000]; // 字典树可能最多的节点数,注意开足了!

int tot = 0;

void CreateTrie(char *str)
{
    int len = strlen(str);
    int now = 0;
    for(int i=0; i<len; i++){
        int idx = str[i]-'a';
        int nxt = Node[now].Next[idx];
        if( nxt == -1){
            nxt = ++tot;
            Node[nxt].init();
            Node[now].Next[idx] = nxt;
        }else Node[nxt].v++;
        now = nxt;
    }
    // Node[now].v = //尾部标志
}

int FindTrie(char *str)
{
    int len = strlen(str);
    int now = 0;
    int nxt;
    for(int i=0; i<len; i++){
        int idx = str[i]-'a';
        if(Node[now].Next[idx] != -1) now = Node[now].Next[idx];
        else return 0;
    }
    return Node[now].v;//返回该返回的值
}
View Code

AC自动机-----------------------------------------------------------------------------------------------------------------------------------------

AC自动机的常规开场: 前置技能 KMP , 字典树  (忘记的盆友看 个 面噢)

(1) 为什么学习AC自动机要先学习 KMP和字典树啊?

这个问题我们需要先来看下AC自动机解决什么问题。

例如 :给定5个单词:say she shr he her,然后给定一个字符串  yasherhs。问一共有多少单词在这个字符串中出现过 (着实经典)

猜你喜欢

转载自www.cnblogs.com/shuaihui520/p/11599847.html
今日推荐