当前位置: 首页 > news >正文

字典树trie

目录

基本概念

结构特点

优势

代码举例

应用场景

复杂度分析

变种


基本概念

       字典树,又称为前缀树或Trie树,是一种树形数据结构,专门用于高效地存储和检索字符串数据集中的键。它的名字来源于单词"retrieval"的中间几个字母,强调了其用于快速检索的特性。

结构特点

1. 
   节点结构 :每个节点包含多个子节点(通常对应字符集的大小),一个指向父节点的指针,以及一个标记表示是否为某个单词的结束。
2. 
   路径表示 :从根节点到任意节点的路径表示一个字符串前缀。
3. 
   共享前缀 :具有相同前缀的字符串在树中共享相同的路径,直到前缀结束。
4. 
   根节点 :不包含字符,仅作为所有字符串的起点。


优势

1. 
   高效检索 :查找时间与字符串长度相关,与数据集大小无关,时间复杂度为O(k),其中k是字符串长度。
2. 
   前缀共享 :节省存储空间,尤其是当有大量具有相同前缀的字符串时。
3. 
   前缀匹配 :很容易实现前缀搜索功能。
4. 
   排序便捷 :按字典序遍历树可以得到所有字符串的排序。

代码举例

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define ALPHABET_SIZE 26/*字典树节点*/
typedef struct TrieNode
{struct TrieNode *children[ALPHABET_SIZE];char character;bool isEndOfWord;} TrieNode;/*创建新节点*/
TrieNode *createTrieNode()
{TrieNode *node;node = malloc(sizeof(TrieNode));node->isEndOfWord = false;int i = 0;while (i < ALPHABET_SIZE){node->children[i] = NULL;i++;}return node;
}/*插入新单词到字典树*/
void insert(TrieNode *root, char *word)
{/*递归地添加单词*///如果单词的长度为0,则返回if ((strlen(word) - 1) != 0){char character = *word;if (root->children[character - 97] == NULL){TrieNode *node = NULL;node = createTrieNode();node->character = character;root->children[character - 97] = node;}word++;insert(root->children[character - 97], word);}else{root->isEndOfWord = true;}return;
}/*在字典树中搜索单词*/
TrieNode *search(TrieNode *root, char *word)
{TrieNode *temp;while (*word != '\0'){char character = *word;if (root->children[character - 97] != NULL){temp = root->children[character - 97];word++;root = temp;}else{printf("No possible words!!\n");return NULL;}}return root;
}/*打印数组*/
void printArray(char chars[], int len)
{int i;for (i = 0; i < len; i++){printf("%c", chars[i]);}printf("\n");
}/*返回所有相关单词*/
void printPathsRecur(TrieNode *node, char prefix[], int filledLen)
{if (node == NULL)return;prefix[filledLen] = node->character;filledLen++;if (node->isEndOfWord){printArray(prefix, filledLen);}int i;for (i = 0; i < ALPHABET_SIZE; i++){printPathsRecur(node->children[i], prefix, filledLen);}
}/*遍历字典树*/
void traverse(char prefix[], TrieNode *root)
{TrieNode *temp = NULL;temp = search(root, prefix);int j = 0;while (prefix[j] != '\0'){j++;}printPathsRecur(temp, prefix, j - 1);
}/*使用字典树文件演示*/#define NUMBER_OF_WORDS (354935)
#define INPUT_WORD_SIZE (100)/*用户输入单词*/
char *receiveInput(char *s)
{scanf("%99s", s);return s;
}int main()
{//读取字典文件int word_count = 0;char *words[NUMBER_OF_WORDS];FILE *fp = fopen("dictionary.txt", "r");if (fp == 0){fprintf(stderr, "Error while opening dictionary file");exit(1);}words[word_count] = malloc(INPUT_WORD_SIZE);while (fgets(words[word_count], INPUT_WORD_SIZE, fp)){word_count++;words[word_count] = malloc(INPUT_WORD_SIZE);}//插入新单词到字典树TrieNode *root = NULL;root = createTrieNode();int i;for (i = 0; i < NUMBER_OF_WORDS; i++){insert(root, words[i]);}while (1){printf("Enter keyword: ");char str[100];receiveInput(str);printf("\n==========================================================\n");printf("\n【********************* Possible Words ********************】\n");// Find the word through the Trietraverse(str, root);printf("\n==========================================================\n");}
}

运行结果:

ubuntu@ubuntu-virtual-machine:~/trie$ ./a.out 
Enter keyword: good luck==========================================================********************* Possible Words ********************
good
goodby
goodbye
goodbyes
goodbys
goodeniaceous
gooder
gooders
goodhap
goodhearted
goodheartedly
goodheartedness
goodhumoredness
goodie
goodies
gooding
goodish
goodishness
goodless
goodlier
goodliest
goodlihead
goodlike
goodliness
goodly
goodman
goodmanship
goodmen
goodnaturedness
goodness
goodnesses
goodnight
goodrich
goods
goodship
goodsire
goodsome
goodtemperedness
goodwife
goodwilies
goodwill
goodwilled
goodwillie
goodwillies
goodwillit
goodwills
goodwilly
goodwily
goodwives
goody
goodyear
goodyish
goodyism
goodyness
goodys
goodyship==========================================================
Enter keyword: 
==========================================================********************* Possible Words ********************
luck
lucked
lucken
luckful
luckie
luckier
luckies
luckiest
luckily
luckiness
lucking
luckless
lucklessly
lucklessness
luckly
lucks
lucky==========================================================
Enter keyword: 

应用场景

1. 
   自动补全 :如搜索引擎、输入法的自动补全功能。
2. 
   拼写检查 :检测输入单词是否存在于词典中。
3. 
   IP路由 :用于快速查找路由表。
4. 
   单词游戏 :如Scrabble、Boggle等游戏中的单词验证。
5. 
   前缀匹配 :如DNA序列分析中的匹配问题。


复杂度分析

时间复杂度 :
  插入:O(k),k为字符串长度
  查找:O(k),k为字符串长度
  删除:O(k),k为字符串长度
空间复杂度 :
  最坏情况:O(n×k),n为字符串数量,k为平均字符串长度
  最好情况:O(∑k),所有字符串共享尽可能多的前缀


变种

1. 
   压缩字典树 :合并只有一个子节点的节点,减少空间使用。
2. 
   二进制字典树 :用于存储二进制数据,常用于异或相关问题。
3. 
   后缀字典树 :用于存储字符串的所有后缀,用于字符串匹配问题。


       字典树是一种非常高效的字符串处理数据结构,尤其适合于有大量共享前缀的字符串集合。尽管在某些情况下可能会占用较多内存,但其出色的检索效率使其在许多应用场景中成为首选。

http://www.dtcms.com/a/317966.html

相关文章:

  • 技术博客:从HTML提取到PDF生成的完整解决方案
  • 奔图P2500NW打印机手机无线连接方法
  • 强化应急通信生命线:遨游三防平板、卫星电话破局极端灾害救援
  • 2.6 sync
  • 2024年测绘程序设计比赛--空间探索性分析(数据为2025年第三次模拟数据)
  • 第二十六天(数据结构:树(补充版程序请看下一篇))
  • 【数据结构与算法】刷题篇——环形链表的约瑟夫问题
  • tmux.conf配置-简易版
  • Java技术栈/面试题合集(15)-RabbitMQ篇
  • 202506 电子学会青少年等级考试机器人四级实际操作真题
  • vue3 vite 使用vitest 单元测试 组件测试
  • Python数据可视化:从基础到高级实战指南
  • 【代码随想录day 12】 力扣 144.145.94.前序遍历中序遍历后序遍历
  • 【数据可视化-82】中国城市幸福指数可视化分析:Python + PyEcharts 打造炫酷城市幸福指数可视化大屏
  • 架构层防护在高并发场景下的实践
  • Linux系统之Docker命令与镜像、容器管理
  • Spring Cloud系列—Eureka服务注册/发现
  • ElasticSearch~DSL常用语法
  • Unity 调节 Rigidbody2D 响应速度的解决方案【资料】
  • CS课程项目设计8:基于Canvas支持AI人机对战的五子棋游戏
  • Lesson 35 Stop thief!
  • MATLAB实现的改进遗传算法用于有约束优化问题
  • Java 工具类的“活化石”:Apache Commons 核心用法、性能陷阱与现代替代方案
  • 03-mysql/redis/apache安装记录
  • 从《中国开源年度报告》看中国开源力量的十年变迁中,Apache SeaTunnel 的跃迁
  • SmartMediaKit 模块化音视频框架实战指南:场景链路 + 能力矩阵全解析
  • LinkedList 深度解析:核心原理与实践
  • uniapp开发中 解决App端 点击input输入框 整体上移
  • DocBench:面向大模型文档阅读系统的评估基准与数据集分析
  • win10/11网络防火墙阻止网络连接?【图文详解】防火墙阻止连接网络的解决方法