精华内容
下载资源
问答
  • Trie

    2020-03-15 16:26:27
    1.Trie的概念: Trie又称字典树,前缀树(事实上前缀树这个名字就很好的解释了Trie的储存方式) 来一张图理解一下Trie的储存方式:(图片来自百度百科) 通过这张图,我们可以看出Trie的特点: Trie没有根节点,也...

    Trie树(字典树)

    1.Trie的概念:
    Trie又称字典树,前缀树(事实上前缀树这个名字就很好的解释了Trie的储存方式)
    来一张图理解一下Trie的储存方式:(图片来自百度百科)
    在这里插入图片描述

    通过这张图,我们可以看出Trie的特点:

    • Trie没有根节点,也就是无根树。
    • 除根节点外,每一个节点的会储存一个字母或单词!
    • 从根节点到每个单词节点的路径上的所有字母连接而成的字符串就是该节点对应的字符串
    • 每个非叶子结点一般都会被多次使用,以节省遍历时的时间效率、
    • 另外,每个节点下面的数字是他们的编号,这个具体在下面再展开

    所以我们可以看出,这是典型的空间换时间

    2.trie的操作

    常用的操作一般有:
    查找(find),插入(insert),删除(isFreeNode)
    这里删除实在是太少见了,所以不展开讨论。

    那些非根节点下面的数字是什么意思?

    事实上,在代码中,我们一般把根节点编号为0,然后把其余节点从1开始编号,然后存在一个数组中(数组的用处是储存每个节点的所有子节点,以便于直接使用下标来存取)

    再具体一点,在我的代码中,用trie[u](结构体)中son[v]的来保存u的那个编号为v的子节点,当然,如果trie[u].son[v]==0,也就代表这个节点不存在,即u没有这个编号为v的子节点
    填完了坑,我们接下来讲(查找和插入)

    前言:一般一道关于Trie的题目,不会只让你去单纯的构造一棵
    Trie树(字典树),一定会有一些附加信息,我们一般根据题目
    意思来定义一个变量,这里我们举一道模板题来加深理解

    题目原题
    题目大意:给你n个名字(name),然后叫你点m的名字,问你
    对于你每点一次名字,这个名字有没有重复点过(输出“REPEAT”)
    反之输出”OK“,还有如果这个名字不正确,也就是它不是n个名字
    中的名字(输出“WRONG”)

    插入:
    这道题是叫我们求得附加信息是有没有出现过,我们用have来
    表示。
    我们先讲讲我们要用的变量及数组

    //cnt表示这个名字是出现了几次
    //son数组表示这个节点的所有情况(因为全是小写字母,所以有26个)
    //表示这个名字是否是n个名字中的名字
    struct node
    {
    	int cnt,son[30];
    	bool have;
    	node() //初始化
    	{
    		cnt=0;
    		memset(son,0,sizeof(son));
    		have=0;
    	} 
    } trie[800010];
    //因为我们是以一个名字的每一个字母为一层,所以是n*每个名字最长的长度(50位)
    然后我们为了保险,再定大点-_-
    

    code(具体解释请看程序):

    void insert(char s[])  
    //这里我没有用指针这种不友好的东西,当然你也可以用*s
    {
    	int u=0,v,len=strlen(s);
    	for(int i=0;i<len;i++)
    	{
    		v=s[i]-'a'; //取得它的编号
    		if(!trie[u].son[v]) trie[u].son[v]=++sum; 
    		//表示这个点没有赋值过
    		u=trie[u].son[v];
    		//继续遍历下一个
    	}
    	trie[u].have=true;  //将这个单词标识为出现过
    }
    

    查找:

    code

    //与上边同理
    //return 1;表示这个名字合理并且第一次出现
    //return 2;表示这个名字合理并且重复出现
    //return 3;表示这个名字不合理(不在这n的名字中)
    int find(char s[]) 
    {
    	int u,v,len=strlen(s);
    	for(int i=0;i<len;i++)
    	{
    		v=s[i]-'a';
    		if(!trie[u].son[v]) return 3; 
    		//如果这个单词中字母没有存储过,则表示没有这个单词
    		u=trie[u].son[v];
    	}
    	if(!trie[u].have) return 3;  
    	//判断这个名字是否在n个名字中
    	if(!trie[u].cnt) //判断这个名字是否是第一次出现
    	{
    		trie[u].cnt++;
    		return 1;
    	}
    	return 2;
    }
    

    完整code

    #include<cstdio>
    #include<iostream>
    #include<string>
    #include<cstring>
    using namespace std;
    struct node
    {
    	int cnt,son[30];
    	bool have;
    	node()
    	{
    		cnt=0;
    		memset(son,0,sizeof(son));
    		have=0;
    	} 
    } trie[800010];
    int sum=0;
    void insert(char s[])
    {
    	int u=0,v,len=strlen(s);
    	for(int i=0;i<len;i++)
    	{
    		v=s[i]-'a';
    		if(!trie[u].son[v]) trie[u].son[v]=++sum;
    		u=trie[u].son[v];
    	}
    	trie[u].have=true;
    }
    int find(char s[])
    {
    	int u,v,len=strlen(s);
    	for(int i=0;i<len;i++)
    	{
    		v=s[i]-'a';
    		if(!trie[u].son[v]) return 3;
    		u=trie[u].son[v];
    	}
    	if(!trie[u].have) return 3;
    	if(!trie[u].cnt)
    	{
    		trie[u].cnt++;
    		return 1;
    	}
    	return 2;
    }
    int main()
    {
    	int n,m;
    	cin>>n;
    	for(int i=1;i<=n;i++)
    	{
    		char name[100];
    		cin>>name;
    		insert(name);
    	}
    	cin>>m;
    	for(int i=1;i<=m;i++)
    	{
    		char name[100];
    		cin>>name;
    		int t=find(name);
    		if(t==1) cout<<"OK"<<endl;
    		else if(t==2) cout<<"REPEAT"<<endl;
    		else cout<<"WRONG"<<endl;
    	}
    	return 0;
    }
    
    
    展开全文
  • trie

    2017-07-04 13:12:50
    trietrie(字典树),用一棵树保存多个字符串,如图:这棵字典树就保存着88条字符串:{to,tea,ted,a,i,in,inn}。从根节点到某特定节点的路径就是对应的字符串。如上图节点编号为红色的点就说明:从根节点到该节点的...

    trie(字典树),用一棵树保存多个字符串,如图:

    trie

    这棵字典树就保存着8条字符串:{to,tea,ted,a,i,in,inn}。

    从根节点到某特定节点的路径就是对应的字符串。如上图节点编号为红色的点就说明:从根节点到该节点的路径为一个保存了的字符串。

    具体实现用trie[i][j]表示节点ij字母到达的点的编号(根的编号为0),如上图:

    trie[0][t]=1,trie[1][o]=2,trie[1][e]=3,trie[3][a]=4,...,trie[9][n]=10

    字母一般用编号0m代替。

    然后用一个val数组保存以该点为结尾的字符串的个数,如上图:val[0]=0,val[1]=0,val[2]=1,val[3]=0,...,val[10]=1

    有时候可能会有多个相同字符串,所以val数组保存的数可能大于零。

    trie程序如下:

    void buildtrie(int x)
    {
        int u=0,m=strlen(str[x]);
        for(int i=0;i<m;i++)
        {
            int v=T(str[x][i]);
            if(trie[u][v]==0)                          //开新节点
            {
                trie[u][v]=++se;
                val[se]=0;
                memset(trie[se],0,sizeof(trie[se]));
            }
            u=trie[u][v];                              //接着往下走
        }
        val[u]++;
    }
    int main()
    {
        scanf("%d",n);
        for(int i=0;i<n;i++)
        {
            scanf("%s",str[i]);
            buildtrie(i);
        }
        return 0;
    }

    例题:UVALive3942(题解

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,612
精华内容 7,844
关键字:

trie