首页 > 代码库 > Trie树(字典树) 个人模版

Trie树(字典树) 个人模版

Trie树的基本实现

字母树的插入(Insert)、删除( Delete)和查找(Find)都非常简单,用一个一重循环即可,即第i 次循环找到前i 个字母所对应的子树,然后进行相应的操作。实现这棵字母树,我们用最常见的数组保存(静态开辟内存)即可,当然也可以开动态的指针类型(动态开辟内存)。至于结点对儿子的指向,一般有三种方法:

1、对每个结点开一个字母集大小的数组,对应的下标是儿子所表示的字母,内容则是这个儿子对应在大数组上的位置,即标号;

2、对每个结点挂一个链表,按一定顺序记录每个儿子是谁;

3、使用左儿子右兄弟表示法记录这棵树。

三种方法,各有特点。第一种易实现,但实际的空间要求较大;第二种,较易实现,空间要求相对较小,但比较费时;第三种,空间要求最小,但相对费时且不易写。

这里采用第一种,速度较快,适合ACM竞赛。

孩子数组大小自定义,此处默认为字母数26;

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>


using namespace std;


typedef struct Trie
{
    int nCount; //该节点前缀 出现的次数
    struct Trie *next[26]; //孩子结点
}Trie;

Trie Memory[1000000]; //先分配内存 malloc费时间
int allocp = 0;

//初始化节点。nCount计数为1,next都是为NULL
Trie * InitNode()
{
    Trie * tmp = &Memory[allocp++];
    tmp->nCount = 1;
    for(int i=0;i<26;i++)
        tmp->next[i]=NULL;
    return tmp;
}
void insertTrie(Trie * * pRoot, char * str)
{
    Trie * tmp = *pRoot;
    int i=0,k;
    //逐个插入
    while(str[i])
    {
        k=str[i]-'a';
        if(tmp->next[k])
        {
            tmp->next[k]->nCount++;
        }else
        {
            tmp->next[k]=InitNode();
        }
        tmp = tmp->next[k];
        i++;
    }
}
int searchTrie(Trie *root,char *str)
{
    if(root==NULL)
        return 0;
    Trie *tmp = root;
    int i=0,k;
    while(str[i])
    {
        k=str[i]-'a';
        if(tmp->next[k])
        {
            tmp = tmp->next[k];
        }else
        {
            return 0;
        }
        i++;
    }
    return tmp->nCount; //返回最后那个结点保存的ncount
}
int main()
{
    int m,n;
    char s[11];
    Trie * root = InitNode();
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%s",s);
        insertTrie(&root,s);
    }
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        scanf("%s",s);
        printf("%d\n",searchTrie(root,s));
    }
    return 0;
}



Trie树(字典树) 个人模版