[模板]前缀树 / 字典树及应用

前缀树 / 字典树是最简单的树了

欠的总是要还的

O(n)算法的多叉树

比较好理解没啥解释的了

用数组模拟 行结点 列指针 cnt记录最大结点编号

直接上代码吧

1.统计单词数 -> 建树
 

int trie[MAXN][26] = {0}, cnt = 1, ans = 0;    //trie树 行结点 列指针

bool wend[MAXN] = {false};        //保存以i节点为结尾的单词是否存在

void insert(char word[])
{
    int len = strlen(word), to = 1;
    
    for(int i = 0; i < len; i++)
    {
        int chn = word[i] - 'a';
        if(!trie[to][chn])
        	trie[to][chn] = ++cnt;
        to = trie[to][chn];
    }

    if(!wend[to])    //计和
        ++ans;

    wend[to] = true;
}

2.单词查询 -> 查询是否能在树中完全匹配

bool wend[MAXN] = {false};        //保存以i节点为结尾的单词是否存在

bool intree(char word[])
{
    int len = strlen(word), to = 1;

    for(int i = 0; i < len; i++)
    {
        int chn = word[i] - 'a';
        if(! trie[to][chn])
            return false;
        to = trie[to][chn];
    }
    return wend[to];  //查询以i节点为结尾的单词是否存在
}

3.存在前缀 -> 查询是否能在树中前缀匹配

例题: http://codevs.cn/problem/4189/

bool intree(char word[]) //只要能扫到单词结尾则必定存在前缀
{
    int len = strlen(word), to = 1;

    for(int i = 0; i < len; i++)
    {
        int chn = word[i] - 'a';
        if(! trie[to][chn])
            return false;
        to = trie[to][chn];
    }
    return true;
}

4.前缀统计1 -> 此单词为字典中多少单词的前缀的和

扫描二维码关注公众号,回复: 6080666 查看本文章

例题: http://acm.hdu.edu.cn/showproblem.php?pid=1251

int trie[MAXN][26] = {0}, sum[MAXN] = {0}, cnt = 1; //sum数组保存到此结点的前缀总和

bool wend[MAXN] = {false};

void insert(char word[])
{
    int len = strlen(word), to = 1;
    
    for(int i = 0; i < len; i++)
    {
        int chn = word[i] - 'a';
        if(!trie[to][chn])
        	trie[to][chn] = ++cnt;
        to = trie[to][chn];
        ++sum[to];                         //计和
    }

    wend[to] = true;
}

int precnt(char word[])
{
    int len = strlen(word), to = 1;

    for(int i = 0; i < len; i++)
    {
        int chn = word[i] - 'a';
        if(!trie[to][chn])
            return 0;                //前缀都扫不完查无此单词 和就不用想了
        to = trie[to][chn];
    }
    
    return sum[to];
}

5.前缀统计2 -> 统计树中有多少单词为当前单词的前缀

例题:http://acm.ncst.edu.cn/problem.php?pid=1421

const int MAXN = 1e6 + 10;

int trie[MAXN][26] = {0}, cnt = 1;

int wend[MAXN] = {0}; //wend本用来标记单词结尾, 现在用来标记以该结点结尾的单词的数量

void insert(char word[])
{
    int len = strlen(word), to = 1;
    
    for(int i = 0; i < len; i++)
    {
        int chn = word[i] - 'a';
        if(!trie[to][chn])
        	trie[to][chn] = ++cnt;
        to = trie[to][chn];
    }

    ++wend[to];
}

int precnt(char word[])
{
    int len = strlen(word), to = 1, ret = 0;

    for(int i = 0; i < len; i++)
    {
        int chn = word[i] - 'a';
        if(!trie[to][chn])
            break;
        to = trie[to][chn];
        ret += wend[to];    //路过的所有结点均为word的前缀 所以加和计算
    }
    
    return ret;
}


猜你喜欢

转载自blog.csdn.net/Zeolim/article/details/88555454