字典树

 

字典树

又称单词查找树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\n",root,j+'a');
            //迭代:
            iter(tree[root][j]);    
            printf("\n");
        }
    }
}

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\n",root,j+'a');
            //迭代:
            iter(tree[root][j]);    
            printf("\n");
        }
    }
}

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实现版本

posted @   -零  阅读(323)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
历史上的今天:
2019-03-08 a标签点击不跳转的几种方法
2019-03-08 Javascript的DOM总结
点击右上角即可分享
微信分享提示