字典树Trie

#include<cstdio>
#include<iostream>
#include<string.h>
using namespace std;
struct trie
{
    int val;//数据域
    trie *next[30]; //儿子节点个数
}*root;
char s[30];
int pos=0,n,m;
int getid(char ch)
{
    return ch-'a';
}
void insert(char *s)
{
    int len=strlen(s);
    trie *pre=root,*temp;
    for(int i=0;i<len;i++)
    {
        int id=getid(s[i]);//每个节点的子节点的排列顺序也是按照字典序从前到后,所以每个字符都有自己的ASCII码
        temp=pre->next[id];//获取儿子节点
        if(!temp)//为空,说明该字符不存在
        {
            temp=(trie*)malloc(sizeof(trie));//开辟空间
            memset(temp,0,sizeof(trie));//初始化,指正也初始化为空
            pre->next[id]=temp;//
        }
        temp->val++;//到达此节点的次数
        pre=temp;//更新节点,将当前节点移动至最新插入的节点上
    }
}
int query(char *s)
{
    int len=strlen(s);
    trie *pre=root,*temp;
    for(int i=0;i<len;i++)
    {
        int id=getid(s[i]);
        temp=pre->next[id];
        if(!temp)//找不到该字符,说明出现0次
            return 0;
        pre=temp;
    }
    return pre->val;//返回该字符出现的次数
}
int main()
{
    root=(trie*)malloc(sizeof(trie));//分配内存
    memset(root,0,sizeof(trie));//初始化
    while(gets(s) && strlen(s))//空行长度为0
    {
        insert(s);
    }
    while(gets(s) && strlen(s))
    {
        cout<<query(s)<<endl;
    }
    return 0;
}
#include<cstdio>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<memory.h>
using namespace std;
int ch[1000005][26],val[1000005],sz;//sz就是size,代表使用到哪一个数组节点了,因为每一次都是取一个结点当做新建节点
//val[i]代表第i个结点出现的次数
char s[30];
void init()
{
    memset(ch[0],0,sizeof(ch[0]));
    sz=1;
}
int getid(char e)
{
    return e-'a';
}
void insert(char *s)
{
    int len=strlen(s);
    int pre=0,next;
    for(int i=0;i<len;i++)
    {
        int id=getid(s[i]);
        next=ch[pre][id]; //得到儿子节点
        if(!next)//为0
        {
            memset(ch[sz],0,sizeof(ch[sz]));//sz为当前第几个字符串
            val[sz]=0;
            ch[pre][id]=sz;
            next=sz++;
        }
        val[next]++;//出现的次数累加
        pre=next;//更新节点位置
    }
}
int query(char *s)
{
    int len=strlen(s);
    int pre=0,next;
    for(int i=0;i<len;i++)
    {
        int id=getid(s[i]);
        next=ch[pre][id];
        if(!next)
            return 0;
        pre=next;
    }
    return val[pre];
}
int main()
{
    init();
    while(gets(s) && strlen(s))
        insert(s);
    while(gets(s) && strlen(s))
        cout<<query(s)<<endl;
    return 0;
}

字典树的应用

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

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

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

使用字典树的好处:

1.利用字符串的公共前缀来节约存储空间。

2.最大限度地减少无谓的字符串比较,查询效率比较高。例如:若要查找的字符长度是5,而总共有单词的数目是26^5=11881376,利用trie树,利用5次比较可以从11881376个可能的关键字中检索出指定的关键字,而利用二叉查找树时间复杂度是O( log2n ),所以至少要进行log211881376=23.5次比较。可以看出来利用字典树进行查找速度是比较快的。

你可能感兴趣的:(字典树Trie)