trie-字典树及实现

【原创】字典树的五种实现方式 字典树(trie树),是一种前缀树,可以在O(m)的时间复杂度匹配目标字符串(m为目标字符串的长度),字典树广泛应用在NLP领域作为词典,具体应用有:分词、词频统计、字符串查询、字符串排序等。 虽然字典树有较低的时间复杂度,但当词典较大时(如中文分词词典),字典树占用的空间非常大,常常难以满足工业应用的需求,因此需要在保持字典树优异的时间复杂度的前提下,尽可能的优化字典树的空间。本文由浅入深,讲解经典字典树、链表字典树、Hash表字典树、双数组字典树、单数组字典树5种字典树实现及各种实现的优缺点。 经典字典 阅读详情

trie树

又称为字典树、单词查找树。是一种树形结构,哈希树的变种。典型应用是用于统计、排序和保存大量的字符串(不仅仅限于字符串),经常被搜索引擎系统用于文本词频统计。trie树是用空间换取时间的典型数据结构。

性质

根节点不包含字符,除了根节点外,每个节点都只包含一个字符;

从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;

每个节点的所有子节点包含的字符都不相同。

基本操作

基本操作有:树的创建、删除;节点的插入、查找、删除(好像这种操作比较少见)。

优点

利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高

缺点

每个节点需要包含一些额外的字段来保存节点信息,浪费空间。

应用

串的快速检索、“串”排序、最长公共前缀

 

trie树实现

本文实现了trie树的创建、删除;字符串的插入、查找、删除。另外,本文限定单词仅仅由26个小写字母组成。具体实现将在本文最后给出完整代码。

结构体设计

typedef struct TrieNode
{
	int isStr; /*word flag*/
	int elemcount; /*word number*/
	int passcount; /*pass by number*/
	struct TrieNode *next[MAX];
}Trie;

其中,isStr 单词结束标记;elemcount是单词被插入的次数;passcount是所有单词经过该节点的次数;next是该节点的孩子节点。

trie树创建

创建trie树与trie树初始化,分开实现。

Trie * trie_malloc();
void trie_init(Trie *p);

trie树删除

删除整棵树,释放其拥有的所有资源

void trie_del(Trie *root);

字符串插入

将字符串s插入trie树root

void trie_insert(Trie *root,const char *s);

字符串查找

从trie树中查找字符串s,如果能找到则返回s在trie中出现的次数(即被插入的次数),否则返回0

int trie_search(Trie *root,const char *s);

字符串删除

trie树中删除字符串s(s是整个单词,并不会删除一个完整单词的一部分)

void trie_node_del(Trie *root, const char *s);

辅助函数

这些辅助函数相当于C++的private成员,仅仅用来辅助实现基本的用户功能。分别为:验证字符串的合法性、根据字符获取在孩子节点中的索引、递归删除trie树、递归删除字符串对应的节点

static int verify_str(const char *s);
static int get_index(char ch);
static void delete_subtrie(Trie **root);
static void delete_node(Trie **node, const char *chr);

具体的代码实现trie.h如下:

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

#define MAX 26
#define IDXERR -1
#define INVALID 0
#define VALID 1

#define true 1
#define false 0

typedef struct TrieNode
{
	int isStr; /*word flag*/
	int elemcount; /*word number*/
	int passcount; /*pass by number*/
	struct TrieNode *next[MAX];
}Trie;

Trie * trie_malloc();
void trie_init(Trie *p);

void trie_insert(Trie *root,const char *s);
int trie_search(Trie *root,const char *s);
void trie_del(Trie *root);
void trie_node_del(Trie *root, const char *s);

static int verify_str(const char *s);
static int get_index(char ch);
static void delete_subtrie(Trie **root);
static void delete_node(Trie **node, const char *chr);

void trie_init(Trie *p)
{
	int i=0;
	if(NULL == p)
		return;
	memset(p,0x0,sizeof(Trie));
	for(i=0;i<MAX;i++)
	{
		p->next[i] = NULL;
	}
	p->isStr = false;
	p->elemcount = 0;
	p->passcount = 0;
}

Trie * trie_malloc()
{
	Trie *temp=(Trie *)malloc(sizeof(Trie));
	return temp;
}

void trie_insert(Trie *root,const char *s)
{
	if(NULL == root || NULL == s || *s == '\0')
		return;
	if(INVALID == verify_str(s))
		return;
	Trie *p = root;
	int idx = 0;
	while(*s!='\0')
	{
		idx = get_index(*s);
		if(NULL == p->next[idx]) 
		{
			Trie *temp = trie_malloc();
			trie_init(temp);
			p->next[idx]=temp;
			p=p->next[idx];   
		}   
		else
		{
			p=p->next[idx];
		}
		s++;
		p->passcount++;
	}
	p->isStr=true;  
	p->elemcount++;
}

int trie_search(Trie *root,const char *s) 
{
	Trie *p=root;
	int idx = 0;
	if(NULL == root || NULL == s)
		return 0;
	while(p != NULL && *s != '\0')
	{
		idx = get_index(*s);
		if(IDXERR == idx)
			return 0;
		p=p->next[idx];
		s++;
	}
	if(p != NULL && true == p->isStr)
		return p->elemcount;
	else
		return 0;
}

void trie_del(Trie *root)
{
        if(NULL == root)
                return;
        delete_subtrie(&root);
}

static int verify_str(const char *s)
{
	if(NULL == s)
		return INVALID;
        while(*s!='\0')
        {
                if(IDXERR == get_index(*s))
                        return INVALID;
                s++;
        }
        return VALID;
}

static int get_index(char ch)
{
        int idx = ch-'a';
        if(idx < 0 || idx >= MAX)
        {
                idx = IDXERR;
        }
        return idx;
}

static void delete_subtrie(Trie **root)
{
	int i = 0;
	if(root != NULL && *root != NULL)
	{
		for(i = 0; i < MAX; i++)
		{
			if((*root)->next[i]!=NULL)
			{
				delete_subtrie(&((*root)->next[i]));
			}
		}
	}
	if(NULL != root)
	{
		free(*root);
		*root = NULL;
	}
}


static void delete_node(Trie **node, const char *chr)
{
	int idx = 0;
	if(NULL == node || NULL == *node || NULL == chr)
		return;
	if(*chr != '\0'&& *(chr+1) != '\0' && *node != NULL)
	{
		chr++;
		idx = get_index(*chr);
		delete_node(&((*node)->next[idx]), chr);           
	}
	if(*node != NULL)
	{
		free(*node);
		*node = NULL;
	}
	return;
} 

void trie_node_del(Trie *root, const char *s)
{
	if(NULL == root || NULL == s || *s == '\0')
		return;
	int elemcount=0;
	Trie *p = root;
        Trie *q = p;
        int remain=0;
        int idx = 0;
	if((elemcount=trie_search(root,s))<= 0)
		return;
	while(*s != '\0' && p != NULL)
	{
		idx = get_index(*s);
		q = p;
		p = p->next[idx];
		remain = p->passcount - elemcount;
		if(remain <= 0)
		{
			delete_node(&p, s);
			q->next[idx] = p; // important
			p = NULL;// can delete "p = NULL"
			break;
		}
		else
		{
			p->passcount = remain;
		}
		s++;
	}
	/*clear word flag*/
	if(p != NULL)
	{
		p->isStr = false;
	}
}


测试代码main.c

#include "trie.h"

#define STR1 "hello"
#define STR2 "hell"
#define STR3 "helloworld"
#define STR4 "world"
#define STARLINE "****"

int main(int argc, char *argv[])
{
	Trie *root= trie_malloc();
	if(NULL == root)
	{
		printf("malloc trie failed\n");
		exit(0);
	}
	trie_init(root);

	/*insert*/
	printf("\n %sinsert string%s\n",STARLINE,STARLINE);
	trie_insert(root,STR1);
	printf("%s\n",STR1);
	trie_insert(root,STR2);
	printf("%s\n",STR2);
	trie_insert(root,STR3);
	printf("%s\n",STR3);
	trie_insert(root,STR4);
	printf("%s\n",STR4);
	trie_insert(root,STR2);
	printf("%s\n",STR2);
	/*search*/
	printf("\n %ssearch string%s\n",STARLINE,STARLINE);
	printf("%s, %d times\n",STR1, trie_search(root,STR1));
	printf("%s, %d times\n",STR2, trie_search(root,STR2));
	printf("%s, %d times\n",STR3, trie_search(root,STR3));
	printf("%s, %d times\n",STR4, trie_search(root,STR4));
	/*delete*/
	printf("\n %sdelete string%s\n",STARLINE,STARLINE);
	trie_node_del(root, STR1);
	printf("%s\n", STR1);
	printf("search %s, %d times\n",STR1, trie_search(root,STR1));

	trie_node_del(root, STR2);
	printf("%s\n", STR2);
	printf("search %s, %d times\n",STR2, trie_search(root,STR2));

	trie_node_del(root, STR3);
	printf("%s\n", STR3);
	printf("search %s, %d times\n",STR3, trie_search(root,STR3));

	trie_node_del(root, STR4);
	printf("%s\n", STR4);
	printf("search %s, %d times\n",STR4, trie_search(root,STR4));

	/*free trie*/
	printf("\n %sfree trie%s\n",STARLINE,STARLINE);
	trie_del(root);
	root = NULL;

	return 0;
}


gcc -g -o test main,c

执行结果如下图:

字典树的C++实现 Implement of trie tree Trie,字典树,又称单词查找树、前缀树,是一种哈希树的变种。应用于字符串的统计与排序,经常被搜索引擎系统用于文本词频统计。   性质: 1.根节点不包含字符,除根节点外的每一个节点都只包含一个字符。 2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。 3.每个节点的所有子节点包含的字符都不相同。 优点是查询快。对于长度为m的键值,最坏情况下只需花费O(m)的时间 阅读详情

相关推荐

实现 Trie 字典树算法 - Java

字典树(Trie)是一种高效的数据结构,常用于字符串的存储和搜索。在本文中,我们将使用 Java 实现 Trie 字典树算法,并提供相应的源代码。在本文中,我们将使用 Java 实现 Trie 字典树算法,并提供相应的源代码。每个节点包含一个布尔变量用于标记是否是单词的结束字符,以及一个包含所有子节点的长度为 26 的 TrieNode 数组。接下来,我们定义 Trie 类,它将作为 Trie 字典树的主要实现。接下来,我们定义 Trie 类,它将作为 Trie 字典树的主要实现。

CyberSparkZ的博客 87

前缀树,查找树,trie数据结构:建前缀树,查字符串,查前缀,删除前缀树中的字符串

1)前缀树=查找树,是重复利用同样前缀的多叉树,节点有pass和end,控制pass和end含义就知道哪些字符有多少个 2)未来大厂面试题中,很多都是前缀树解决的,但是遇到前缀树的题目,很难,多见,多总结把

weixin_46838716的博客 1197

【java】Trie树及Java实现 Trie树(字典树)的介绍及Java实现

我是在我们项目中发现有人使用这个字典树的,因为没有见过,所以来学习一下。Trie树,又称为前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。【这点很重要:位置决定】。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。如下是一棵典型的Trie树:Trie的来源是Retrieval,它常用于前缀匹配和词频统计。

九师兄 382

【数据结构】 字典树

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

这里是阿安的博客 2235

用Trie树实现词频统计和单词查询

一个简单的C语言程序:用Trie树实现词频统计和单词查询

医学影像分割入门:为什么U-Net至今仍是肝脏CT肿瘤分割的‘首选’?

本文探讨了U-Net在肝脏CT肿瘤分割中的持久优势,分析了其轻量化设计、对称架构和跳跃连接如何完美适配医学影像的小样本、高精度需求。通过对比实验和实战建议,揭示了U-Net在肝脏肿瘤分割任务中超越新模型的根本原因,并提供了PyTorch实现和部署技巧。

weixin_38166931的博客 518

字典树(Trie)

字典树,英文名 trie。顾名思义,就是一个像字典一样的树。

cyyyyds857的博客 990

保姆级避坑指南:用Livox官方工具搞定Mid-360多雷达自动标定(附源码Bug修复)

本文详细解析了使用Livox官方工具进行Mid-360多雷达自动标定的全流程,包括环境搭建、工具链配置、关键Bug修复及数据采集最佳实践。重点解决了PointCloudMapper.cpp边界检查缺失和calibration.cpp点云显示问题,提供了实用的代码修复方案和标定质量评估指标,帮助开发者高效完成激光雷达标定任务。

weixin_29053695的博客 281

【字符串】Trie字典树

Trie字典树 例题 给出n个字符串,以及m个询问。每次询问读入一个字符串,求该字符串是多少个字符串的前缀 每个字符串长度小于10^2,n和m小于10^5。 【样例输入】 4 anan amn aman anann 3 ana ama a 【样例输出】 2 1 4 朴素算法:暴力搜索,对于每个询问,把所有的n个字符串搜索一遍,统计答案。时间复杂度大于10^10。显然,这样时间是非常大的。 如果要优化时间的话,我们就可以使用字典树。 1.什么是字典树? 字典树,又叫...

zsjzliziyang的博客 432

Shopee商品详情页反爬实战:手把手逆向x-sap-Ri和x-sap-Sec请求头加密

本文详细解析了Shopee商品详情页反爬机制中x-sap-Ri和x-sap-Sec请求头参数的加密逻辑,通过JS逆向技术手把手教你定位加密入口、分析哈希算法与对称加密实现,并提供完整实战案例和应对反爬策略的高级技巧,助力开发者突破电商平台数据采集难点。

weixin_27875131的博客 1826

计算机视觉——SIFT特征匹配

文章目录一、SIFT特征检测原理1.1基本思想1.2二、SIFT特征检测图片兴趣点三、SIFT特征检测描述子匹配四、输入图片检测与之 一、SIFT特征检测原理 1.1基本思想 1.2 二、SIFT特征检测图片兴趣点 代码: 检测结果: 三、SIFT特征检测描述子匹配 四、输入图片检测与之 ...

weixin_43869874的博客 3855

Java实现字典树 Trie

字典树又称为前缀树,是n叉树的特殊形式,广泛应用于统计和排序大量的字符串,它可以很大程度减少无所谓的字符比较,查询效率较高,Trie的核心思想是空间换时间,利用字符串的公共前缀提高查询效率

m0_62701287的博客 2061

光致发光(Photoluminescence, PL)入门版

关于光致发光的实际应用做出一些解释。

sinat_40546227的博客 1万+

【字典树】用python实现Trie树

字典树常用做高效的文本词语保存,适用于敏感词过滤、关键词提取等场景。在字典树中相同前缀的词之间共享相同的树节点和路径。 字典树结构一般包括如下功能和属性:(1)构建;(2)添加;(3)删除;(4)前缀统计;(5)搜索 实现一:通过字典的嵌套来实现 class Trie(object): """ 实现1:通过python自带的字典结构 具有如下基本功能: (1)根据一组words进行TrieTree的构建 (2)添加某个word (3)查询某个word

guofei_fly的博客 2334

【开关电源篇】开关电源——只需这三个阶段,从电源小白到维修大神

🔌 该篇为的原创文章跳转目录,小二持续更新跳转链接,尽情关注!

2301_81299416的博客 2390

一次把 PRIV mode 讲透:从 ABAP 内存分配链路到定位与治理

ABAP系统进入PRIV模式的本质是Extended Memory耗尽时转向Heap内存的应急机制。该现象会导致工作进程被独占,系统吞吐量下降。触发条件包括系统EM资源池耗尽或单个用户超过配额阈值。关键参数em/address_space_MB和ztta/roll_extension需协同调整。典型症状包括SM50显示PRIV状态、响应延迟和内存dump。治理需双管齐下:系统侧合理配置内存参数,代码侧优化内存使用模式,如分页处理、减少大内表操作和下推聚合逻辑。PRIV模式应作为异常信号而非常态目标,健康系统

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 200

python 实现Trie字典树算法

Trie字典树(Trie Tree),又称为前缀树(Prefix Tree)、单词查找树或字典树,是一种多叉树结构。根节点不包含字符,除根节点外每一个节点都只包含一个字符。从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。每个节点的所有子节点包含的字符都不相同。利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。单词检索、统计和排序字符串、字符串前缀搜索等。常见的应用场景包括单词自动补全、串的快速检索、单词自动完成、最长公共前缀查找以及串排序等。

luthane的博客 796

【YOLO系列】YOLOv11详解:模型结构、损失函数、训练方法及代码实现

YOLOv11在目标检测领域实现重大突破,通过动态骨干网络(Dyna-Backbone)和FPN++架构,在保持高帧率(≥60FPS)的同时提升小目标检测精度(AP_S提升5.6%)。创新采用CIoU++损失函数和类别平衡Focal Loss,结合Mosaic-Plus数据增强,参数量减少18%至6.5M。实验显示,该模型在COCO数据集上实现更高mAP,特别适合移动端部署,Jetson Xavier平台能耗比优化至3.2W·ms⁻¹,支持目标检测、实例分割等多任务场景。关键创新包括动态深度调整和双向特征金

一碗白开水一 3444

Trie树/字典树的原理及实现[C/C++]

我们学习过很多字符串查询的算法,暴搜,KMP、BM、RK等字符串匹配算法,这些都是在文本中去查找我们的模式串。我们在搜索引擎的输入栏中输入时,常常仅输入了前缀,下面就给我们列出了几个含有此前缀的搜索项,这难道也是我们的字符串匹配算法吗?通过对字典树Trie的学习,相信会对此有所理解。字典树,又称trie树,是一种树形的数据结构。可以用作词频统计,利用字符串的公共前缀来减少查询时间。一般用来查找某个字符串S是否在一个字符串集合中。

EQUINOX1的博客 882

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

字典树(Trie)的java实现

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

Together_CZ的博客 3357

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Trie(字典树)详解与C++实现

文章目录参考资料Trie Introduction(介绍字典树)C++实现Trie 应用 参考资料 甜姨的力扣题解:https://zhuanlan.zhihu.com/p/120150816 力扣官方题解:https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-sh...

要相信光 8803

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

利用Trie(字典树)实现敏感词过滤算法

Trie(字典树),正如它的名字一样,其主要的作用就是来存储字符串的,用它来实现字符串的查找效率比较高,查找的时间复杂度主要和它的元素(字符串的长度)O(W)相关,但是消耗的内存也比较大。 字典树主要应用于: 字符串的检索 词频统计 字符串的排序 利用Trie实现敏感词过滤器主要有下面三个步骤: 定义前缀树 根据敏感词,初始化前缀树 编写过滤敏感词的算法 定义和初始化前缀树 根节点没有字...

weixin_41927235的博客 4966

Java字典树Trie实现

字典树Trie java实现

zhaohui blog 216

C++实现Trie字典树

一、前言 这篇文章来源于HihoCode的#1014题,此处为链接 二、Trie字典树 字典树,顾名思义就是将单词存在一个树结构中,用来对单词进行存储和查找功能,并且可以统计出以某一特定字符串为前缀共有多少单词,本文中只涉及英文单词。 字典树是一个26叉树,每一个父节点都有26个子节点,分别对应了26个英文字母,树的结构大致如下: 理所当然的根节点不代表任何字母,作为一个空节点。那么每个

u013352994的专栏 842

字典树-Trie实现

一、字典树 Trie,又称前缀树或字典树,是一棵有根树。该数据结构中,将Trie[26] 与英文26个字母一一对应,即Trie[0]代表字符a。 特点:字符串内存消耗小,字符串查询快 // 子节点 private Trie[] children; // 是否结束 private boolean isEnd; 二、API 1、初始化 Trie /** * 初始化 */ public Trie() { // 英文字母26个,创建...

Dily_Su的博客 304

实现字典树 Trie 的基本操作

实现字典树 Trie 的基本操作 字典树可以快速的匹配多个字符串的共同前缀, 下面是一些字典树常见的应用: trie可以看做是一个多叉树,在每个结点中存放了必要的信息,对所传入的参数进行快速的判读 class trieNode{ public: shared_ptr<trieNode> next[26]; bool is_word; char value; trieNode() = default; trieNode(char ch):is_word

li123_123_的博客 203
上一篇: 代码量统计脚本
下一篇: 红黑树实现
IT_Linux
博客等级 码龄14年 31粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值