字典树

字典树,通常解决大量拥有相同前缀的字符串问题,有时候也是二进制数问题(字典树起初是链表写,但是比较麻烦,感觉数组更好一些,链表无非就是next换成*next,空间用的时候定义)

 

第一次听学长讲字典树的时候讨论这么一个问题,就是网址假如有1e10个,但是每个网址前面都有http,所以要是每个都直接存,光http就要花费4*1e10空间,但是如果要是用字典树压缩一下,就变成了4

 

字典树如果要存储的字符串有26种,其实就是26叉树,m种,就是m叉树

开始树是空的,每个节点其实都代表一个字符,并且每个节点往下最多有m个节点

每个节点都是一个结构体,每个点类似链表一样(链表只能指向下一个,而这个能指向m个),该点可能还要记录 是不是某个(或者是多少个)字符串的尾

Struct s

{
int v;

    Int next[26];

}f[1005];

v通常根据情况而定,有时候可以记录当前为结尾的字符串有多少,也可以是含有当前的前缀的字符串有多少

通常next没有值的时候可以赋值成0,因为这是一棵树,所以他要是往0(根)跳是不可能的。

Int tot

tot通常用于记录结构体数组已经使用多少了,所以当需要定义新的的时候,放入到f[tot]即可

对于只包含26个字符的字典树,通常开一个next[26]的数组(如果对于二进制数字只包含01串的话,next[2]即可)

假如输入字符串ACAA以后

 

Hdu1251,开始给定一堆字符串,让你找某个字符串是多少个给定字符串的前缀

#include<stdio.h>
#include<string.h>
int len;
struct s
{
    int v;
    int next[27];
}f[1000005];
char str[105];
int tot;
void mem(int x)
{
    f[x].v=0;
    for(int i=0;i<26;i++)
        f[x].next[i]=0;
}
void add()
{
    int z=0,zz;///z从根开始,一直记录到达的节点
    for(int i=0;i<len;i++)
    {
        zz=str[i]-'a';
        if(!f[z].next[zz])///如果之前没有这条路的话,就建立一个
        {
            mem(tot);///清空结构体
            f[z].next[zz]=tot++;
        }
        z=f[z].next[zz];
        f[z].v++;///因为一会要记录前缀有多少个,所以每个字符串都把自己的前缀+1即可
    }
}
int query()
{
    int z=0,zz;
    for(int i=0;i<len;i++)
    {
        zz=str[i]-'a';
        if(!f[z].next[zz])///说明没有以他为前缀的
            return 0;
        z=f[z].next[zz];
    }
    return f[z].v;
}
int main()
{
    mem(0);
    tot=1;
    int zt=0;
    while(gets(str))
    {
        len=strlen(str);
        if(len==0)
        {
            zt=1;
         continue;
        }
        if(zt)
        printf("%d\n",query());
        else
          add();
    }
}

 

posted @ 2018-12-27 11:43  注册以后还能改吧  阅读(251)  评论(0编辑  收藏  举报