字典树模板

老久没写博客了,跟一波风。

去年暑假集训的时候学的字典树,ac自动机什么的,用的不是很多,该忘还是得忘,毕竟属于数据结构(我也想全面developing啊),我专精的图论有空再发嘛

寒假集训开始,打算先复习一下以前学的各种算法,然后再去专研图论的东西(学了一堆,脑子里面却已经忘得零零散散,再去学新东西着实顶不住那零散的阴影)

还好,当初学的很认真,现在简单回想复习一下,懂还是没问题的,内化为自己的理解。

示例模板题:http://www.fjutacm.com/Problem.jsp?pid=2050

自己的理解融于代码之中了,另外也推荐一篇别人写的(我就是馋人家的好图懒得搬):https://blog.csdn.net/weixin_39778570/article/details/81990417

复制代码
#include<cstdio>
#include<cstring>
#define N 100009
#define mt(x) memset(x,0,sizeof x)
char s[N][30],S[30];//存字符串
int tree[N*5][30];//字典树
int index[N*5],num,cnt;//下标辅助
/*
index用于 指出根节点所示的字符串 在s字符串数组中的下标
cnt 用于辅组index依序储存根节点 
num 用于指向在tree中新的根节点所示值

也就是说:
创建tree时,根节点对应++num去标记,
完整字符串对应index中cnt去标记 
(也就是在index数组中,特定的num值转存下标为++cnt,表示这里是第cnt+1个字符串) 
然后,要在s字符串数组中找指定字符串
首先,查找完整字符串的cnt下标,也就是num的值,原字符串遍历找到对应num
得到num之后,我们已经用index数组标记了num所示的字符串在s字符串数组中的下标为cnt
也即, s[index[num]],就是我们要找的字符串 
*/
void Init()
{
    mt(tree);mt(s);mt(index);
    num=0;cnt=0;
} 
void Insert()
{
    int t=0;//根结点值 
    int i=0,k=0;//区分两字符串
    while(S[i++]!=' ');
    k=i;//标记区分下标,k指向value字符串第一个字符 
    while(S[i])
    {
        int id=S[i++]-'a';
        if(!tree[t][id])tree[t][id]=++num;//不存在,则创建分支,标记为++num
        t=tree[t][id];//转移结点 
    }
    index[t]=++cnt;
    strncpy(s[cnt],S,k-1);//复制字符串 
    /*
    for(int i=0;i<k-1;++i)
        s[cnt][i]=S[i];
    //*/ 
}
int Find()
{
    int t=0,i=0;
    while(S[i])
    {
        int id=S[i++]-'a';
        if(!tree[t][id])return 0;
        t=tree[t][id];
    }
    return t;
} 
int main()
{
    Init();
    while(gets(S)&&S[0])
        Insert();
    while(~scanf("%s",S))
    {
        int i=Find();
        printf("%s\n",i?s[index[i]]:"eh");
    }
    return 0;
}
标准字典树
复制代码

另外,因为是两两匹配,很容易让人想到STL里的一个关联容器Map,在题目数据很水或者时限不小的情况也可以这么写,这题也行。

(两种的解法时间是倍数关系,字典树tql)

复制代码
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
int main()
{
    map<string,string>p;
    char x[30],y[30];
    while(gets(x)&&x[0])
    {
        sscanf(x,"%s%s",y,x);
        p[x]=y;
    }
    while(gets(x))
        cout<<(p[x]==""?"eh":p[x])<<endl;
    return 0;
}
Map水水水
复制代码

另外,复习的时候想到了,通过另外一个数组来标识一个数组的下标这种写法很常见,类似索引的意思

最经典的就是链式前向星存图,里面的head数组与num搭配,指定边的下标

好处的话,能理解桶排的妙处都能理解这样写的好处吧,字典树这里面也用到了,将字典树里的结点值存在一个自增数组里,再用自增值取指向结果字符串数组中的下标

也就这么个转换关系,初次理解可能会觉得有点绕,但真的不难,也就【x->三元关系->y】这种意思。

posted @   Renhr  阅读(48)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示