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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务 人工智能AI 物联网智慧工地云平台源码

目录 ​编辑 智慧工地架构 智慧工地系统 智慧工地云平台功能模块 1、基础数据管理 2、考勤管理 3、安全隐患管理 4、视频监控 5、塔吊监控 6、升降机监控 7、移动端数据推送 智慧工地管理平台子系统构成 智慧工地物联网解决方案&#xff0c;对工地施工安全人员、设…

数据库分库分表中间件选择

目前分库分表的中间件有三种设计思路&#xff0c;分别是&#xff1a; 采用分散式架构&#xff0c;适用于用Java开发的高性能轻量级OLTP应用程序&#xff0c;以Sharding-JDBC为代表。采用中间层Proxy架构&#xff0c;提供了静态输入和所有语言支持&#xff0c;适用于OLAP应用程…

毁灭交易账户的最快途径:摒弃复仇心态

虽然这听起来像是漫威宇宙最新的超级英雄传奇&#xff0c;但复仇者交易员绝不是英雄。 相反&#xff0c;复仇(报复性)交易者是让人害怕和避免的。他们是那些不承认他们的交易正在亏损&#xff0c;或者拒绝接受他们正在亏损&#xff0c;没有达到他们的日常目标的交易者。这些反英…

Leetcode—63. 不同路径 II【中等】

2024每日刷题&#xff08;115&#xff09; Leetcode—63. 不同路径 II 动态规划算法思想 实现代码 class Solution { public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int m obstacleGrid.size();int n obstacleGrid[0].size();…

音频提取使用什么方法?视频提取音频

在数字技术与多媒体日益普及的今天&#xff0c;音频提取已成为一个常见且重要的任务。无论是为了制作视频、编辑音乐&#xff0c;还是进行语音识别和分析&#xff0c;我们都需要从原始材料中提取音频。那么&#xff0c;音频提取通常使用什么方法呢&#xff1f; 1. 使用专业的音…

springboot项目打成含crud操作的sdk集成到springboot启动引擎项目

一 sdk配置操作 1.1 结构 sdk项目目录中只有基础的service类以及mybatis操作数据库的相关文件&#xff0c;service类中包含查询数据库的方法。 说明&#xff1a; 1.2 sdk的pom打包配置 作为公共项目打成jar供其他项目引用&#xff0c;注意被引入的项目不能使用默认的maven…

【MySQL】MySQL5.7版本安装与配置

目录 官网下载配置环境变量添加自定义配置打开命令窗口执行安装命令执行初始化命令启动MySQL服务设置MySQL密码 官网 MySQ官网地址&#xff1a;https://www.mysql.com/ 下载 选择DOWNLOADS 拉到下面 选择MySQL Community Server 默认是8.0版本&#xff0c;选择Archives…

芯片行业ERP管理全流程科普

在现代芯片行业中&#xff0c;企业资源规划(ERP)管理已经成为提升效率、优化资源配置和增强竞争力的关键工具。那么&#xff0c;芯片行业ERP管理的全流程是怎样的呢? 首先&#xff0c;ERP管理的起点是需求分析与规划。在这一阶段&#xff0c;企业需要明确自身的业务需求&#…

可靠性技术之链路聚合(手工模式)

-以太网链路聚合Eth-Trunk:简称链路聚合&#xff0c;通过将多个物理接口捆绑成为一个逻辑接口&#xff0c;可以在不进行硬件升级的条件下&#xff0c;达到增加链路带宽的目的&#xff0c;并且具有防环功能。 在未配置链路聚合时&#xff0c;STP会自动阻塞一条链路&#xff0c;从…

【Unity】实现从Excel读取数据制作年份选择器

效果预览&#xff1a; 此处利用Excel来读取数据来制作年份选择器&#xff0c;具体步骤如下。 如果只是制作年份选择器可以参考我这篇文章&#xff1a;构建简单实用的年份选择器&#xff08;简单原理示范&#xff09; 目录 效果预览&#xff1a; 一、 Excel准备与存放 1.1 …

SpringBoot整合rabbitmq-直连交换机队列(二)

说明&#xff1a;本文章主要是Direct定向/直连类型交换机的使用&#xff0c;它的大致流程是将一个队列绑定到一个直连交换机上&#xff0c;并赋予一个路由键 routingkey&#xff0c;当一个消息携带着路由值为routingkey&#xff0c;这个消息通过生产者发送给交换机时&#xff0…

c++学习记录 vector容器—插入和删除

函数原型&#xff1a; push_back(ele); //尾部插入元素elepop_back(); //删除最后一个元素insert(const_iterator pos,ele); …