Trie树(字典树)

Posted waryan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Trie树(字典树)相关的知识,希望对你有一定的参考价值。

Trie树

概要:

  字典树算法主要是对字符串进行处理,最后形成形如下图的trie树

  字典树主要用来查询前缀出现次数,字符串以前缀代表,查找单词,对某个单词的操作和询问

技术图片

 

  在形成字典树的时候遵循的原则:

  1.根节点0不标记如图所示,单词是否出现以单词的下个节点来作为判断如果上所示的‘$‘,实际上也就是每个字符都是存在边上的

  2.单词的插入,首先单词cat进行插入,然后下一个下一个,若单词的前缀相同的时候用的是同一个节点的分支

  3.一个节点最多就26个分支所以模板代码的数组开的[][26]

技术图片

 

 

  trie树模板:

 

  进行单词的插入:

void Insert(char s[],int rt)
{
    for(int i=0;s[i]!=;++i)
    {
        int id=s[i]-a;
        if(!trie[rt][id])//现在插入的之前未出现过
            trie[rt][id]=++tot;
        rt=trie[rt][id];
//        ++sum[rt];
    }
//    vis[rt]=1;
}

 

  单词是否出现过-注意如果不是查询前缀还要做的一步就是查询这个节点结束的位置在vis中是不是一个单词的结束点

 

int Find(char s[],int rt)
{
    for(int i=0;s[i]!=;++i)
    {
        int id=s[i]-a;
        if(trie[rt]id]==0) return 0;//无此节点
        rt=trie[rt][id];
    }
    return 1;
}

 

   查询前缀出现的次数

int SearchNumber(char s[],int rt)//寻找前缀数
{
    for(int i=0;s[i]!=;++i)
    {
        int id=s[i]-a;
        if(!trie[rt][id]) return 0;
        root=trie[rt][id];
    }
    return sum[rr];//找到前缀

}

 

  查询能代表单词的前缀

void ask(char s[],int rt)//用前缀来代表整个单词
{
    for(int i=0;s[i]!=;++i)
    {
        if(sum[rt]==1) break;
        int id=s[i]-a;
        printf("%c",s[i]);
        rt=trie[rt][id];
    }
}

 

const int maxn=1e6+10;
int trie[maxn][27];
int tot=1,n;
//bool vis[maxn];//检查是否为单词
int sum[maxn];

  

注意:单词的前缀和单词的结束节点都是在trie[rt][id]存好后的下一个节点,具体看上面的图分析

 

 应用:

  1.查询能代表单词的前缀

  POJ2001-Shortest Prefixes

#include <iostream>
#include<algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include<map>
#include<set>
#include<sstream>
#define INF 0x3f3f3f3f
#define DOF 0x7f7f7f7f
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef long long ll;
using namespace std;
const int maxn=1e6+10;
int trie[maxn][27];
int tot=1,n;
//bool vis[maxn];//检查是否为单词
char s[1010][35];
int sum[maxn];
void Insert(char s[],int rt)
{
    for(int i=0;s[i]!=;++i)
    {
        int id=s[i]-a;
        if(!trie[rt][id])//现在插入的之前未出现过
            trie[rt][id]=++tot;
        rt=trie[rt][id];
//        ++sum[rt];
    }
//    vis[rt]=1;
}

int Find(char s[],int rt)
{
    for(int i=0;s[i]!=;++i)
    {
        int id=s[i]-a;
        if(trie[rt]id]==0) return 0;//无此节点
        rt=trie[rt][id];
    }
    return 1;
}

int SearchNumber(char s[],int rt)//寻找前缀数
{
    for(int i=0;s[i]!=;++i)
    {
        int id=s[i]-a;
        if(!trie[rt][id]) return 0;
        root=trie[rt][id];
    }
    return sum[rr];//找到前缀

}

void ask(char s[],int rt)//用前缀来代表整个单词
{
    for(int i=0;s[i]!=;++i)
    {
        if(sum[rt]==1) break;
        int id=s[i]-a;
        printf("%c",s[i]);
        rt=trie[rt][id];
    }
}
int main()
{
//    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
    int n=0;
    while(scanf("%s",s[++n])!=EOF)
        Insert(s[n],0);
    for(int i=1;i<=n;++i)
    {
        printf("%s ",s[i]);
        ask(s[i],0);
        printf("
");
    }
//    system("pause");

}

 

附上学习时候看的博客:https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html

 

以上是关于Trie树(字典树)的主要内容,如果未能解决你的问题,请参考以下文章

trie树(字典树)

前缀树(字典树/Trie) -----Java实现

数据结构——trie树(字典树)

Trie树(字典树)

LeetCode 208. 实现 Trie (前缀树)

01字典树