trie树(前缀树)

前缀树

  • 1. 前缀树的的介绍
  • 2.前缀树的实现
    • 2.1插入功能
    • 2.2删除功能
    • 2.3查找前缀和查找单词功能
    • 2.4 哈希表版本

1. 前缀树的的介绍

在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。

2.前缀树的实现

如何实现一颗前缀树呢?这里有两种实现的方法,对应了不同的情况。

我们首先来定义一下前缀树的节点,我们让每一个根节点有两个值,一个为pass,一个为end,pass表示经过这个节点的次数,end表示走到叶子节点的次数(也就是这个单词出现的次数)。

我们先看看这棵树的结构。比如我们插入字符串{“aa”,“aaa”,“bba”,“ssba”},我们看看这颗树的结构。

在这里插入图片描述

现在我们模拟这个过程来写代码
先来定义好节点

struct TreeNode // 创建结点
{
	TreeNode *next[26];
	int end;
	int pass;
	TreeNode() // 初始化结点
	{
		end = 0;
		path = 0;
		for(int i=0;i<26;i++)
		next[i]=NULL;
	}
};

下面我们实现树的部分,我们就储存一个头节点和所需要的接口

class Trie
{
private:
	TreeNode* root;
public:
	Trie()
	{
		root = new TreeNode;
	}
	void insert_Node(string word); // 插入
	void Delete_Node(string word); // 删除
	int  search(string word); // 查找
	int prefixNumber(string word);//查找有多少以word作为前缀的单词
};

2.1插入功能

void Trie::insert_Node(string wrod)
{
	if (wrod == "") return;

	int idx = 0;
	TreeNode* node = root;
	root->pass++;

	for (int i = 0; i < wrod.size(); i++)
	{
		idx = wrod[i] - 'a';
		if (node->next[idx]==nullptr)
		node->next[idx] = new TreeNode;

		node = node->next[idx];
		node->pass++;
	}
	node->end++;
}

2.2删除功能

//这个函数java的可以不用写,因为Java有JVM垃圾回收机制。
void Delete(TreeNode* node)
{
	if (node == NULL)
		return;

	for (int num = 0; num < 26; num++)
	{
		if (node->next[num])
		{
			Delete(node->next[num]);
		}
	}
	delete(node);
	node=NULL;
}

void Trie::Delete_Node(string word)
{
	if (!search(word))
		return;

	int index = 0;
	TreeNode* node = root;
	node->pass--;

	for (int i = 0; i < word.size(); i++)
	{
		index = word[i] - 'a';
		if (--node->next[index]->pass == 0)
		{
			// Java的直接将 node。next[index] = NULL  即可
			Delete(node->next[index]);
			node->next[index] = NULL;
			return;
		}
		node = node->next[index];
	}
	node->end--;
}

2.3查找前缀和查找单词功能

int Trie::prefixNumber(string word)
{
	if (word == "") return 0;

	int idx = 0;
	TreeNode* node = root;
	for (int i = 0; i < word.size(); i++)
	{
		idx = word[i] - 'a';
		if (node->next[idx] == nullptr) return 0;
		node = node->next[idx];
	}
	return node->pass;
}
int Trie::search(string word)
{
	if (word == "") return 0;

	int idx = 0;
	TreeNode* node = root;
	for(int i=0;i<word.size();i++)
	{ 
		idx = word[i] - 'a';
		if (node->next[idx] == nullptr) return 0;
		node = node->next[idx];
	}
	return node->end;
}

2.4 哈希表版本

如何单词不只有26个小写字母,我们该如何去实现呢,我们可以通过哈希表去进行映射来实现。
只需要以ASIII作为key,代码稍微改动一下就可以了。

#include <iostream>
#include <string>
#include <algorithm>
#include <unordered_map>
using namespace std;

struct TreeNode
{
	int pass;
	int end;
	unordered_map<int, TreeNode*> next;
	TreeNode()
	{
		pass = 0;
		end = 0;
	}
		
};

class Trie
{
private:
	TreeNode* root;
public:
	Trie()
	{
		root = new TreeNode;
	}
	void insert_Node(string word); // 插入
	void Delete_Node(string word); // 删除
	int  search(string word); // 查找
	int prefixNumber(string word);//查找有多少以word作为前缀的单词
};

void Trie::insert_Node(string wrod)
{
	if (wrod == "") return;

	int idx = 0;
	TreeNode* node = root;
	root->pass++;

	for (int i = 0; i < wrod.size(); i++)
	{
		idx = (int)wrod[i];
		if (!node->next.count(idx))
		{
			node->next[idx] = new TreeNode;
		}

		node = node->next[idx];
		node->pass++;
	}
	node->end++;
}

int Trie::search(string word)
{
	if (word == "") return 0;

	int idx = 0;
	TreeNode* node = root;
	for(int i=0;i<word.size();i++)
	{ 
		idx = (int)word[i];
		if (!node->next.count(idx)) return 0;
		node = node->next[idx];
	}
	return node->end;
}
//这个函数java的可以不用写,因为Java有JVM垃圾回收机制。
void Delete(TreeNode* node)
{
	if (node == NULL)
		return;

	for (int num = 0; num < 26; num++)
	{
		if (node->next[num])
		{
			Delete(node->next[num]);
			
		}
	}
	delete(node);
	node = NULL;
}

void Trie::Delete_Node(string word)
{
	if (!search(word))
		return;

	int index = 0;
	TreeNode* node = root;
	node->pass--;

	for (int i = 0; i < word.size(); i++)
	{
		index = (int)word[i];
		if (--node->next[index]->pass == 0)
		{
			// Java的直接将 node。next[index] = NULL  即可
			Delete(node->next[index]);
			node->next[index] = NULL;
			return;
		}
		node = node->next[index];
	}
	node->end--;
}

int Trie::prefixNumber(string word)
{
	if (word == "") return 0;

	int idx = 0;
	TreeNode* node = root;
	for (int i = 0; i < word.size(); i++)
	{
		idx = (int)word[i];
		if (!node->next.count(idx)) return 0;
		node = node->next[idx];
	}
	return node->pass;
}

int main()
{
	Trie tr;
	tr.insert_Node("aad");
	tr.insert_Node("jjafp");
	tr.insert_Node("jjdafp");
	tr.insert_Node("jjdafp");
	tr.insert_Node("jjafp");
	tr.insert_Node("jjdap");

	cout << tr.search("jjdafp") << endl;
	cout << tr.prefixNumber("j") << endl;
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/416108.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《Spring Security 简易速速上手小册》第1章 Spring Security 概述(2024 最新版)

文章目录 1.1 Spring Security 的重要性1.1.1 基础知识详解1.1.2 主要案例&#xff1a;用户认证与授权1.1.3 拓展案例 1&#xff1a;OAuth2 社交登录1.1.4 拓展案例 2&#xff1a;JWT 认证 1.2 Spring Security 的核心特性1.2.1 基础知识详解1.2.2 主要案例&#xff1a;基于角色…

11.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-接管游戏接收网络数据包的操作

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;接管游戏发送数据的操作 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;8256eb53e8c16281bc1a29cb8d26d352bb5bbf4c 代…

Android Duplicate class 排除重复类

一、起因&#xff1a; 在迭代开发的时候&#xff0c;发现2个ijk很多类重复。但又2个库实现的功能是不一样&#xff0c;目前不能合并。但又想保留2个功能。需要排除其中一个库。 二、报错如何下图&#xff1a; 三、解决方法&#xff1a; 3.1 在terminal 也就是命令行处输入 …

js 面试 什么是WebSockets?HTTP和HTTPS有什么不同?web worker是什么?

概念&#xff1a; webSocket 是一种在客户端和服务端之间建立持久连接的协议&#xff0c;它提供全双工通信通道&#xff0c;是服务器可以主动向客户端推送数据&#xff0c;同时也可以接受客户端发送的数据。 1 webSocket与https区别&#xff1f; 在网络通信中&#xff0c;We…

【mysql版本修改】

1、使用telnet确认当前mysql版本号 telnet <MySQL服务器IP地址> <MySQL端口号> telnet 192.168.38.20 33062、使用strings查看/usr/sbin/mysqld中包含版本号的字符串 # 查看/usr/sbin/mysqld文件中是否包含对应的版本号 strings /usr/sbin/mysqld | grep 5.7.30 …

Unity | 动态读取C#程序集实现热更新

目录 一、动态语言 二、创建C#dll 1.VS中创建一个C#语言的库工程 2.添加UnityEngine.dll的依赖 3.编写代码&#xff0c;生成dll 三、Unity使用dll 一、动态语言 计算机编程语言可以根据它们如何将源代码转换为可以执行的代码来分类为静态语言和动态语言。 静态语言&…

Spark Bloom Filter Join

1 综述 1.1 目的 Bloom Filter Join&#xff0c;或者说Row-level Runtime Filtering&#xff08;还额外有一条Semi-Join分支&#xff09;&#xff0c;是Spark 3.3对运行时过滤的一个最新补充   之前运行时过滤主要有两个&#xff1a;动态分区裁剪DPP&#xff08;开源实现&am…

ISO_IEC_18598-2016自动化基础设施管理(AIM)系统国际标准解读(一)

██ ISO_IEC_18598-2016是什么标准&#xff1f; ISO/IEC 18598国际标准是由ISO&#xff08;国际标准化组织&#xff09;/IEC&#xff08;国际电工委员会&#xff09;联合技术委员会1-信息技术的第25分委员会-信息技术设备互连小组制定的关于信息基础设施自动化管理的国际标准&…

C++中atomic的使用

atomic使用 概述介绍使用场景头文件atomic的使用创建load()store()exchange()compare_exchange_weakcompare_exchange_strong&#xff08;&#xff09;fetch_add()fetch_sub()fetch_and()fetch_or()fetch_xor() 示例实现代码运行结果 概述 本文只要讲述C11中atomic的使用&…

一文读懂Prometheus和Grafana的区别(适合小白)

Prometheus和Grafana是两种开源软件&#xff0c;分别用于监控和可视化数据。它们的主要功能和特点如下&#xff1a; Prometheus 监控系统&#xff1a;Prometheus是一个专门用于收集和存储时间序列数据的监控系统。它可以从各种目标&#xff08;如服务器、数据库等&#xff09…

Spring中的事务和事务的传播机制

事务是一组操作的集合&#xff0c;不可以被分割。事务会把所有的操作作为一个整体&#xff0c;这组操作要么全部成功&#xff0c;要么全部失败。 事务有三种操作&#xff1a; 开启事务&#xff1b;提交事务&#xff1b;回滚事务。 如果代码的执行逻辑是这样&#xff1a; 开…

NutUI + taro +vue 开发遇到的问题 使用popup组件 内部元素滚动遇到的的问题

1 popup 弹出内容时 弹出的框内元素数据很长需要滚动时 本地可以正常滚动 打包成小程序后无法滚动 如这样的免责条款内容 代码如下 解决办法 1 把2处的单位换成百分比 弹框能滚动但是 是popup 里面所有的元素都一起滚动 导致标题都滚走了 2 scroll-y 改成&#xff1a; :scrol…

Excel数据表定制分组排序

实例需求&#xff1a;某学校体育活动统计表如下图左侧表格所示&#xff0c;数据按照班级排列&#xff0c;现在需要根据如下规格对表格进行排序 “幼儿”班级排列在表格最后按照“次数”降序排列“幼儿”班级同样按“次数”降序排列 排序结果如下图中右侧表格所示。 示例代码…

GDB之(8)GDB-Server远程调试

GDB之(8)GDB-Server远程调试 Author&#xff1a;Once Day Date&#xff1a;2024年2月27日 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章请查看专栏: Linux实践记录_Once-Day的博客-CSDN博客 参考文档: 用GDB调试程序 _CSDN博客 _陈皓GDB: The GNU Project Debugger…

UE4c++ ConvertActorsToStaticMesh ConvertProceduralMeshToStaticMesh

UE4c ConvertActorsToStaticMesh 创建Edior模块&#xff08;最好是放Editor模块毕竟是编辑器代码&#xff09;创建蓝图函数UBlueprintFunctionLibraryUTestFunctionLibrary.hUTestFunctionLibrary.cpp:.Build.cs 目标:为了大量生成模型&#xff0c;我们把虚幻带有的方法迁移成函…

【数据结构与算法】回溯法解题20240229

【数据结构与算法】回溯法解题20240229 一、46. 全排列1、以[1,2,3]为例&#xff0c;抽象成树形结构2、回溯三部曲 二、LCR 084. 全排列 II1、以[1,1,2]为例&#xff0c;抽象成树形结构 三、面试题 08.07. 无重复字符串的排列组合四、面试题 08.08. 有重复字符串的排列组合 一、…

基于视觉识别的自动采摘机器人设计与实现

一、前言 1.1 项目介绍 【1】项目功能介绍 随着科技的进步和农业现代化的发展&#xff0c;农业生产效率与质量的提升成为重要的研究对象。其中&#xff0c;果蔬采摘环节在很大程度上影响着整个产业链的效益。传统的手工采摘方式不仅劳动强度大、效率低下&#xff0c;而且在劳…

163邮箱SMTP端口号及服务器地址详细设置?

163邮箱SMTP端口号是什么&#xff1f;163邮件SMTP设置教程&#xff1f; 除了基本的邮箱账号和密码外&#xff0c;还需要了解SMTP服务器地址和端口号&#xff0c;以及相应的设置。这些设置对于确保邮件能够顺利发送至关重要。下面&#xff0c;蜂邮EDM将详细介绍163邮箱SMTP端口…

http和https的区别是什么?

–前言 传输信息安全性不同、连接方式不同、端口不同、证书申请方式不同 一、传输信息安全性不同 1、http协议&#xff1a;是超文本传输协议&#xff0c;信息是明文传输。如果攻击者截取了Web浏览器和网站服务器之间的传输报文&#xff0c;就可以直接读懂其中的信息。 2、h…

《Redis 设计与实现》读书概要

注&#xff1a; 《Redis 设计与实现》一书基于 Redis 2.9 版本编写&#xff0c;部分内容已过时&#xff0c;过时之处本文会有所说明。本文为读书笔记&#xff0c;部分简单和日常使用较少的知识点未记录。原书网页版地址 https://redisbook.com/ 一、底层数据结构 SDS(Simple Dy…