字典树小结

字典树,又称单词查找树,Trie树,是一种树形结构,典型应用是用于统计,排序和保存大量的字符串,所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度的减少无谓的字符串比较,查询效率比哈希表高。

它有三个基本性质,根节点不包含字符,除根节点外每一个节点都只包含一个字符,从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串,每个节点的所有子节点包含的字符都不相同。


字典树的插入,删除和查找都非常简单,用一个一重循环即可。
1. 从根节点开始一次搜索
2. 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索
3. 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索
4. 迭代过程...
5. 在某个节点处,关键词的所有字母已被取出,则读取附在该节点上的信息,即完成查找

字典树的应用
1.字典树在串的快速检索中的应用。
给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。
在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。

2. 字典树在排序方面的应用
给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出
用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可

3. 字典树在最长公共前缀问题的应用
对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为最近公共祖先问题(以后补上)。

HDU1251题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1251

/*裸的字典树应用,自己慢慢体会,注意内存的分配,一不小心就会RE或MLE*/
#define mann 1000010
#define INF 0x3f3f3f3f
typedef long long LL;
struct node
{
    int num;
    struct node *next[26];
};
struct node *root;
node *build()
{
    struct node *p=(node*)malloc(sizeof(node));
    p->num=0;
    for(int i=0; i<26; i++)
        p->next[i]=NULL;
    return p;
}
void Insert(char s[])
{
    struct node *p=root;
    int len=strlen(s);
    for(int i=0; i<len; i++)
    {
        if(p->next[s[i]-'a']==NULL)
            p->next[s[i]-'a']=build();
        p=p->next[s[i]-'a'];
        p->num++;
    }
}
int query(char s[])
{
    struct node *p=root;
    int len=strlen(s);
    for(int i=0; i<len; i++)
    {
        if(p->next[s[i]-'a']==NULL)
            return 0;
        p=p->next[s[i]-'a'];
    }
    return p->num;
}
int main()
{
    char s[10];
    root=build();
    while(gets(s))
    {
        if(s[0]=='\0')
            break;
        Insert(s);
    }
    while(~scanf("%s",s))
    {
        printf("%d\n",query(s));
    }
}
/*数组实现*/
#define mann 1000005
#define INF 0x3f3f3f3f
typedef long long LL;
int ch[mann][27];
int val[mann];
int node;
void add(char s[])
{
    int u=0,len=strlen(s),c;
    for(int i=0; i<len; i++)
    {
        c=s[i]-'a';
        if(!ch[u][c])
        {
            memset(ch[node],0,sizeof(ch[node]));
            val[node]=0;
            ch[u][c]=node++;
        }
        u=ch[u][c];
        val[u]++;
    }
}
int query(char s[])
{
    int u=0,len=strlen(s),c;
    for(int i=0; i<len; i++)
    {
        c=s[i]-'a';
        if(!ch[u][c])
            return 0;
        else
            u=ch[u][c];
    }
    return val[u];
}
int main()
{
    char s[30];
    node=1;
    memset(ch[0],0,sizeof(ch[0]));
    memset(val,0,sizeof(val));
    while(1)
    {
        gets(s);
        if(s[0]=='\0')
            break;
        add(s);
    }
    while(scanf("%s",s)!=EOF)
    {
        int ans=query(s);
        printf("%d\n",ans);
    }
}

这里有一些字典树入门的经典体型 https://vjudge.net/contest/120748#overview
做每道题都应该多想想,总结出自己的模板,这样才会有更大的进步
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值