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://xiahunao.cn/news/2815242.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

177基于matlab的基于S函数的变步长自适应滤波算法

基于matlab的基于S函数的变步长自适应滤波算法&#xff0c;比传统的算法收敛速度更快。传统的LMS算法中&#xff0c;权值向量实时地被更新。这些更新可能会由于噪声的影响而变得不稳定。SVSLMS算法是一种改进的LMS算法&#xff0c;它采用了矢量处理的概念&#xff0c;利用信号和…

Qt中的QGraphicView和QGraphicScene简单使用

概述&#xff1a;我们利用QGraphicView和QGraphicScene来实现一个简单的视频播放器&#xff0c;然后上面悬浮一些操作的控件&#xff0c;看看怎么来实现。 1、CcTestVideoPlayer类 模拟播放器类&#xff0c;继承QGraphicScene 1.1 CcTestVideoPlayer.h #pragma once#include…

【低代码开发_RuoYi_框架】RuoYi框架_前端页面部署/搭建

开源软件的影响力 随着信息技术的快速发展&#xff0c;开源软件已经成为软件开发的趋势&#xff0c;并产生了深远的影响。开源软件的低成本、可协作性和透明度等特点&#xff0c;使得越来越多的企业和个人选择使用开源软件&#xff0c;促进了软件行业的繁荣。然而&#xff0c;…

代码随想录刷题训练营day25:LeetCode(216)组合总和III、LeetCode(17)电话号码的字母组合

代码随想录刷题训练营day25&#xff1a;LeetCode(40)组合总和 II、LeetCode(216)组合总和III、LeetCode(17)电话号码的字母组合 LeetCode(40)组合总和 II 题目 代码 import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util…

高性能Server的基石:reactor反应堆模式

业务开发同学只关心业务处理流程。但是我们开发的程序都是运行服务端server上&#xff0c;服务端server接收到IO请求后&#xff0c;是如何处理请求并最终进入业务流程的呢&#xff1f;这里不得不提到reactor反应堆模型。reactor反应堆模型来源于大师Doug Lea在 《Sacalable io …

linux下查看某个命令在哪里个安装包程序下,以ifconfig命令举例子

yum list | grep net-tools &#xff08;查看yum安装列表中有没有安装指定的软件工具&#xff09;

USB Series A and Series B 连接器的引脚定义

参考《Universal Serial Bus Specification, Revision 2.0, April 27, 2000》

C++——类和对象(2):构造函数、析构函数、拷贝构造函数

2. 类的6个默认成员函数 我们将什么成员都没有的类称为空类&#xff0c;但是空类中并不是什么都没有。任何类中都会存在6个默认成员函数&#xff0c;这6个默认成员函数如果用户没有实现&#xff0c;则会由编译器默认生成。 6个默认成员函数包括&#xff1a;负责初始化工作的构造…

python dictionary 字典

Python 字典 字典是另一种可变容器模型&#xff0c;且可存储任意类型对象。 字典的每个键值 key>value 对用冒号 : 分割&#xff0c;每个对之间用逗号(,)分割&#xff0c;整个字典包括在花括号 {} 中 ,格式如下 d {key1 : value1, key2 : value2, key3 : value3 }dict 作…

RocketMQ入坑指南(五):SpringBoot集成RocketMQ和具体使用方式

前言 经过前面几部分的教程&#xff0c;大家应该已经对RocketMQ有了一个全面的认识&#xff0c;建议仔细阅读前几章的内容&#xff0c;可以更好的理解这次的内容&#xff0c;接下来&#xff0c;我们通过代码来演示一下SpringBoot如何集成并使用RocketMQ发送消息 一、SpringBo…

Linux笔记--用户与用户组

Linux系统是一个多用户多任务的操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员(root)申请一个账号&#xff0c;然后以这个账号的身份进入系统。 用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪&#xff0c;并控制他们对系…

Unity中URP下实现水体(水面反射)

文章目录 前言一、原理1、法一&#xff1a;使用立方体纹理 CubeMap&#xff0c;作为反射纹理使用2、法二&#xff1a;使用反射探针生成环境反射图&#xff0c;所谓反射的采样纹理 二、实现水面反射1、定义和申明CubeMap2、反射向量需要什么3、计算 N ⃗ \vec{N} N 4、计算 V ⃗…

【C++私房菜】序列式容器的迭代器失效问题

目录 一、list的迭代器失效 二、vector的迭代器失效 1、空间缩小操作 2、空间扩大操作 三、总结 在C中&#xff0c;当对容器进行插入或删除操作时&#xff0c;可能会导致迭代器失效的问题。所谓迭代器失效指的是&#xff0c;原先指向容器中某个元素的迭代器&#xff0c;在…

STM32_DS18B20_1_芯片简介及初始化配置

DS18B20介绍 DS18B20数字温度计提供9位到12位摄氏度的温度测量&#xff0c;并具有非易失性&#xff0c;用户可编程的上下触发点的报警功能。DS18B20通过1线总线进行通信&#xff0c;根据定义&#xff0c;该总线只需要一条数据线&#xff0c;即可与中央微处理器进行通信…

5G双域快网

目录 一、业务场景 二、三类技术方案 2.1、专用DNN方案 2.2、ULCL方案&#xff1a;通用/专用DNNULCL分流 2.3、 多DNN方案-定制终端无感分流方案 漫游场景 一、业务场景 初期双域专网业务可划分为三类业务场景&#xff0c;学校、政务、文旅等行业均已提出公/专网融合访问需…

每日五道java面试题之spring篇(九)

目录&#xff1a; 第一题. 说一下Spring的事务传播行为第二题. 说一下 spring 的事务隔离&#xff1f;第三题. Spring AOP and AspectJ AOP 有什么区别&#xff1f;AOP 有哪些实现方式&#xff1f;第四题. JDK动态代理和CGLIB动态代理的区别第五题. 解释一下Spring AOP里面的几…

nginx实现http反向代理及负载均衡

目录 一、代理概述 1、代理概念 1.1 正向代理&#xff08;Forward Proxy&#xff09; 1.2 反向代理&#xff08;Reverse Proxy&#xff09; 1.3 正向代理与反向代理的区别 2、同构代理与异构代理 2.1 同构代理 2.2 异构代理 2.3 同构代理与异构代理的区别 二、四层代…

VL817-Q7 USB3.0 HUB芯片 适用于扩展坞 工控机 显示器

VL817-Q7 USB3.1 GEN1 HUB芯片 VL817-Q7 USB3.1 GEN1 HUB芯片 VIA Lab的VL817是一款现代USB 3.1 Gen 1集线器控制器&#xff0c;具有优化的成本结构和完全符合USB标准3.1 Gen 1规范&#xff0c;包括ecn和2017年1月的合规性测试更新。VL817提供双端口和双端口4端口配置&…

Linux NFC 子系统剖析

1.总览 linux源码中NFC在net/nfc下&#xff0c;文件结构如下图&#xff1a; hci&#xff1a;Host Controller Interface 主要是针对NFC的主机-控制器接口协议 nci&#xff1a;NFC Controller Interface 主要是NFC的控制器接口协议&#xff0c;用于NFCC(NFC Controller)和DH(…

【Go语言】Go语言中的切片

Go语言中的切片 1.切片的定义 Go语言中&#xff0c;切片是一个新的数据类型数据类型&#xff0c;与数组最大的区别在于&#xff0c;切片的类型中只有数据元素的类型&#xff0c;而没有长度&#xff1a; var slice []string []string{"a", "b", "c…