字典树

字典树

又称单词查找树Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高,缺点是内存开销大。 

字典树与字典很相似,当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明字典树里没有该单词,如果在就在该字母的孩子节点里找是不是有单词的第二个字母,没有说明没有该单词,有的话用同样的方法继续查找.字典树不仅可以用来储存字母,也可以储存数字等其它数据。

 c语言实现

#include <stdio.h>
#include <string.h>
    

#define NodeSize 100 //100000
#define CHARSIZE 26  //26
int flag[NodeSize]={0};//是否以该节点结尾,大小为节点数量
int tree[NodeSize][CHARSIZE];//每一个节点都有26个子节点,如果有大写字母则为52,加上数字就是62
int cnt=0;//记录已经存储字母的节点数量

void Insert(char s[])
{
    int root=0;
    int i;
    //遍历
    for(i=0;s[i];i++)
    {    
        //得到0-25范围的整数,代表a-z
        int id=s[i]-'a';
        //判断该节点是否被赋值
        //如果为-1,说明该节点还未存储字母,就需要创建新节点
        if(tree[root][id]==-1) 
        {    
            //创建一个新节点
            tree[root][id]=++cnt;
        }
        //如果存在直接指向这个节点,如果不存在,指向创建的新节点
        //指向的是下标
        root=tree[root][id];
    }
    //设置该节点的结束标志
    flag[root]= 1;
}
int Search(char s[])
{
    int root=0;
    int i;
    for(i=0;s[i];i++)
    {
        int id=s[i]-'a';
        if(tree[root][id]==-1) return 0;
        root=tree[root][id];
    }
    //判断该节点是否为结束标志位
    if(flag[root]){
        return 1;
    }else{
        return 0;
    }
}

void Init(){
    int i;
    int j;
    for(i=0;i<NodeSize;i++){
        for(j=0;j<CHARSIZE;j++){
            tree[i][j] = -1;
        }
    }
}
    
    
int main()
{
    Init();
    char s1[5] = "fggf";
    char s2[4] = "fbs";
    char s3[6] = "fb";
    //插入字符串
    Insert(s1);
    //插入字符串
    Insert(s2);
    //查找字符串
    int flag = Search(s3);
    if(flag){
        printf("字符串存在");
    }else{
        printf("字符串不存在");
    }
    return 0;
}

基本操作

插入:在字典树中插入单词

1.每次插入从根节点开始

int root=0;

2.遍历单词

 for(i=0;s[i];i++)
    {    
       。。。
    }

3.得到当前字母在此节点下的位置,每个节点有26个子节点。

int id=s[i]-'a';

4.判断该节点是否已经存储字母,如果存储,直接指向该节点,如果没有,新增节点,并指向新增节点。

     //判断该节点是否被赋值
        //如果为-1,说明该节点还未存储字母,就需要创建新节点
        if(tree[root][id]==-1) 
        {    
            //创建一个新节点
            tree[root][id]=++cnt;
        }
        //如果存在直接指向这个节点,如果不存在,指向创建的新节点
        //指向的是下标
        root=tree[root][id];

5.结束插入后,在此节点的位置标记单词结束标志。

   //设置该节点的结束标志
    flag[root]= 1;
void Insert(char s[])
{
    int root=0;
    int i;
    //遍历
    for(i=0;s[i];i++)
    {    
        //得到0-25范围的整数,代表a-z
        int id=s[i]-'a';
        //判断该节点是否被赋值
        //如果为-1,说明该节点还未存储字母,就需要创建新节点
        if(tree[root][id]==-1) 
        {    
            //创建一个新节点
            tree[root][id]=++cnt;
        }
        //如果存在直接指向这个节点,如果不存在,指向创建的新节点
        //指向的是下标
        root=tree[root][id];
    }
    //设置该节点的结束标志
    flag[root]= 1;
}

查找:在字典树中查找单词是否存在

int Search(char s[])
{
    int root=0;
    int i;
    for(i=0;s[i];i++)
    {
        int id=s[i]-'a';
        if(tree[root][id]==-1) return 0;
        root=tree[root][id];;
    }
    //判断该节点是否为结束标志位
    if(flag[root]){
        return 1;
    }else{
        return 0;
    }
}

最重要的功能:已知前缀,查所有出现的单词。

void iter(int root){
    int j;
    for(j=0;j<26;j++){
        //tree[root][j]存储的是节点位置
        if(tree[root][j] != -1){
            printf("%d:%c
",root,j+'a');
            //迭代:
            iter(tree[root][j]);    
            printf("
");
        }
    }
}

int locate(char s[])
{
    int root=0;
    int i;
    for(i=0;s[i];i++)
    {
        int id=s[i]-'a';
        if(tree[root][id]==-1) return 0;
        root=tree[root][id];
    }
    //判断该节点是否为结束标志位
    if(flag[root]){
           return 0;
    }
    iter(root);
    return 1;
}
#include <stdio.h>
#include <string.h>
    

#define NodeSize 100 //100000
#define CHARSIZE 26  //26
int flag[NodeSize]={0};//是否以该节点结尾,大小为节点数量
int tree[NodeSize][CHARSIZE];//每一个节点都有26个子节点,如果有大写字母则为52,加上数字就是62
int cnt=0;//记录已经存储字母的节点数量

void Insert(char s[])
{
    int root=0;
    int i;
    //遍历
    for(i=0;s[i];i++)
    {    
        //得到0-25范围的整数,代表a-z
        int id=s[i]-'a';
        //判断该节点是否被赋值
        //如果为-1,说明该节点还未存储字母,就需要创建新节点
        if(tree[root][id]==-1) 
        {    
            //创建一个新节点
            tree[root][id]=++cnt;
        }
        //如果存在直接指向这个节点,如果不存在,指向创建的新节点
        //指向的是下标
        root=tree[root][id];
    }
    //设置该节点的结束标志
    flag[root]= 1;
}
int Search(char s[])
{
    int root=0;
    int i;
    for(i=0;s[i];i++)
    {
        int id=s[i]-'a';
        if(tree[root][id]==-1) return 0;
        root=tree[root][id];
    }
    //判断该节点是否为结束标志位
    if(flag[root]){
        return 1;
    }else{
        return 0;
    }
}

void iter(int root){
    int j;
    for(j=0;j<26;j++){
        //tree[root][j]存储的是节点位置
        if(tree[root][j] != -1){
            printf("%d:%c
",root,j+'a');
            //迭代:
            iter(tree[root][j]);    
            printf("
");
        }
    }
}

int locate(char s[])
{
    int root=0;
    int i;
    for(i=0;s[i];i++)
    {
        int id=s[i]-'a';
        if(tree[root][id]==-1) return 0;
        root=tree[root][id];
    }
    //判断该节点是否为结束标志位
    if(flag[root]){
           return 0;
    }
    iter(root);
    return 1;
}


void Init(){
    int i;
    int j;
    for(i=0;i<NodeSize;i++){
        for(j=0;j<CHARSIZE;j++){
            tree[i][j] = -1;
        }
    }
}
    
    
int main()
{
    Init();
    char s1[5] = "fggf";
    char s2[4] = "fbs";
    char s3[6] = "f";
    //插入字符串
    Insert(s1);
    //插入字符串
    Insert(s2);
    //查找字符串
    locate(s3);
   
    return 0;
}
源码

更多阅读:

python实现版本

原文地址:https://www.cnblogs.com/-wenli/p/12442678.html