Trie树(c++实现)
原理
先看个例子,存储字符串abc、ab、abm、abcde、pm可以利用以下方式存储
上边就是Trie树的基本原理:利用字串的公共前缀来节省存储空间,最大限度的减少无谓的字串比较。
应用
Trie树又称单词查找树,典型的应用是用于统计,排序和保存大量的字符串(不仅用于字符串),所以经常被搜索引擎系统用于文本词频的统计。
设计
trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。
结点可以设计成这样:
class trieNode {public:trieNode() : terminableSize(0), nodeSize(0) { for(int i = 0; i < Size; ++i) children[i] = NULL; }~trieNode(){for(int i = 0; i < Size; ++i){delete children[i];children[i] = NULL;}}public:int terminableSize; //存储以此结点为结尾的字串的个数int nodeSize; //记录此结点孩子的个数trieNode* children[Size]; //该数组记录指向孩子的指针 };
图示
树设计成这样:
template<int Size, class Type> class trie {public:typedef trieNode<Size> Node;typedef trieNode<Size>* pNode;trie() : root(new Node) {}template<class Iterator>void insert(Iterator beg, Iterator end);void insert(const char *str);template<class Iterator>bool find(Iterator beg, Iterator end);bool find(const char *str);template<class Iterator>bool downNodeAlone(Iterator beg);template<class Iterator>bool erase(Iterator beg, Iterator end);bool erase(const char *str);int sizeAll(pNode);int sizeNoneRedundant(pNode);public:pNode root;private:Type index; };
index字串索引利用(char % 26) 得到,这样'a' % 26 = 19, 'b' % 26 = 20
实现
插入
以插入abc、ab为例
]
删除
删除结点,首先查找此字串是否在树中,如果在树中,再查找此结点以下的部分是不是都是只有一个孩子,并且每个结点只有叶子结点是结束结点,如果不是继续往下重复上边过程。
统计字串个数
分两种情况
- 计算重复的字串的个数:是结束结点,此时加的是terminabel的个数
- 计算不重复的字串的个数:是结束结点,此时加的是1(当terminabel>0)的个数
参考代码
#include <iostream> #include <cstring> using namespace std;template<int Size> class trieNode {public:trieNode() : terminableSize(0), nodeSize(0) { for(int i = 0; i < Size; ++i) children[i] = NULL; }~trieNode(){for(int i = 0; i < Size; ++i){delete children[i];children[i] = NULL;}}public:int terminableSize;int nodeSize;trieNode* children[Size]; };template<int Size, class Type> class trie {public:typedef trieNode<Size> Node;typedef trieNode<Size>* pNode;trie() : root(new Node) {}template<class Iterator>void insert(Iterator beg, Iterator end);void insert(const char *str);template<class Iterator>bool find(Iterator beg, Iterator end);bool find(const char *str);template<class Iterator>bool downNodeAlone(Iterator beg);template<class Iterator>bool erase(Iterator beg, Iterator end);bool erase(const char *str);int sizeAll(pNode);int sizeNoneRedundant(pNode);public:pNode root;private:Type index; };template<int Size, class Type> template<class Iterator> void trie<Size, Type>::insert(Iterator beg, Iterator end) {pNode cur = root;pNode pre;for(; beg != end; ++beg){if(!cur->children[index[*beg]]){cur->children[index[*beg]] = new(Node);++cur->nodeSize;}pre = cur;cur = cur->children[index[*beg]];}++pre->terminableSize; } template<int Size, class Type> void trie<Size, Type>::insert(const char *str) {return insert(str, str + strlen(str)); }template<int Size, class Type> template<class Iterator> bool trie<Size, Type>::find(Iterator beg, Iterator end) {pNode cur = root;pNode pre;for(; beg != end; ++beg){if(!cur->children[index[*beg]]){return false;break;}pre = cur;cur = cur->children[index[*beg]];}if(pre->terminableSize > 0)return true;return false; }template<int Size, class Type> bool trie<Size, Type>::find(const char *str) {return find(str, str + strlen(str)); }template<int Size, class Type> template<class Iterator> bool trie<Size, Type>::downNodeAlone(Iterator beg) {pNode cur = root;int terminableSum = 0;while(cur->nodeSize != 0){terminableSum += cur->terminableSize;if(cur->nodeSize > 1)return false;else //cur->nodeSize = 1 {for(int i = 0; i < Size; ++i){if(cur->children[i])cur = cur->children[i];}}}if(terminableSum == 1)return true;return false; } template<int Size, class Type> template<class Iterator> bool trie<Size, Type>::erase(Iterator beg, Iterator end) {if(find(beg, end)){pNode cur = root;pNode pre;for(; beg != end; ++beg){if(downNodeAlone(cur)){delete cur;return true;}pre = cur;cur = cur->children[index[*beg]];}if(pre->terminableSize > 0)--pre->terminableSize;return true;}return false; }template<int Size, class Type> bool trie<Size, Type>::erase(const char *str) {if(find(str)){erase(str, str + strlen(str));return true;}return false; }template<int Size, class Type> int trie<Size, Type>::sizeAll(pNode ptr) {if(ptr == NULL)return 0;int rev = ptr->terminableSize;for(int i = 0; i < Size; ++i)rev += sizeAll(ptr->children[i]);return rev; }template<int Size, class Type> int trie<Size, Type>::sizeNoneRedundant(pNode ptr) {if(ptr == NULL)return 0;int rev = 0;if(ptr->terminableSize > 0)rev = 1;if(ptr->nodeSize != 0){for(int i = 0; i < Size; ++i)rev += sizeNoneRedundant(ptr->children[i]);}return rev; }template<int Size> class Index {public:int operator[](char vchar) { return vchar % Size; } };int main() {trie<26, Index<26> > t;t.insert("hello");t.insert("hello");t.insert("h");t.insert("h");t.insert("he");t.insert("hel");cout << "SizeALL:" << t.sizeAll(t.root) << endl;cout << "SizeALL:" << t.sizeNoneRedundant(t.root) << endl;t.erase("h");cout << "SizeALL:" << t.sizeAll(t.root) << endl;cout << "SizeALL:" << t.sizeNoneRedundant(t.root) << endl; }
结果
技术实现细节
1. 对树的删除,并不是树销毁结点,而是通过结点自身的析构函数实现
2. 模版类、模版函数、非类型模版可以参考:http://www.cnblogs.com/kaituorensheng/p/3601495.html
3. 字母的存储并不是存储的字母,而是存储的位置,如果该位置的指针为空,则说明此处没有字母;反之有字母。
4. terminableNum存储以此结点为结束结点的个数,这样可以避免删除时,不知道是否有多个相同字符串的情况。
Trie树(c++实现)相关推荐
- usaco Cowxor (trie 树)
没想到trie树还可以用在这上面,厉害厉害. [分析]这是字母树的经典应用.首先因为是求xor的最大值,可以用前缀和计算xor值,然后n^2枚举即可. [cpp] view plaincopy for ...
- 字符串匹配算法 -- AC自动机 基于Trie树的高效的敏感词过滤算法
文章目录 1. 算法背景 2. AC自动机实现原理 2.1 构建失败指针 2.2 依赖失败指针过滤敏感词 3. 复杂度及完整代码 1. 算法背景 之前介绍过单模式串匹配的高效算法:BM和KMP 以及 ...
- 字符串匹配数据结构 --Trie树 高效实现搜索词提示 / IDE自动补全
文章目录 1. 算法背景 2. Trie 树实现原理 2.1 Trie 树的构建 2.2 Trie树的查找 2.3 Trie树的遍历 2.4 Trie树的时间/空间复杂度 2.5 Trie 树 Vs ...
- POJ 2418 Hardwood Species(trie 树)
题目链接 开始想用map的,字典序不会搞,还是老老实实的用trie树把.好久没写了,忘得差不多了. 1 #include <iostream> 2 #include <cstdio& ...
- 【bzoj3261】最大异或和 可持久化Trie树
题目描述 给定一个非负整数序列 {a},初始长度为 N. 有M个操作,有以下两种操作类型: 1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1. 2.Q l r x: ...
- 算法 | 动画+解析,轻松理解「Trie树」
Trie这个名字取自"retrieval",检索,因为Trie可以只用一个前缀便可以在一部字典中找到想要的单词. 虽然发音与「Tree」一致,但为了将这种 字典树 与 普通二叉树 ...
- 浅谈树形结构的特性和应用(上):多叉树,红黑树,堆,Trie树,B树,B+树......
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 上篇文章我们主要介绍了线性数据结构,本篇233酱带大家看看 无所不 ...
- Trie树合并 + SG函数 ---- BZOJ4730. Alice和Bob又在玩游戏(动态开点Trie 树上全局异或标记 + 合并 + 博弈论)
题目大题 题目大意: 解题思路: 首先我们对于子树u的SG函数为SG函数为SG函数为 ⨁是异或和\bigoplus是异或和⨁是异或和 SG[u]=mex{⨁w∈(w的父亲在u到v的路径上)SG[w]∣ ...
- SZUACM集训字符串基础总结: 字符串最小表示 ,KMP, EXKMP, Manracher, Trie树,字符串的hash; 附带一写常见的运用技巧,邝斌大佬的板子和例题[持续更新]
第一部分 字符串的匹配<-------->KMP 模式匹配:子串的定位运算称为串的模式匹配或串匹配. 假设有两个串S,T,设S为主串,也称正文串,T为子串,也称为模式,在主串S中查找与模式 ...
- BZOJ 1590.Secret Message 秘密信息(Trie树) [Usaco2008 Dec]【BZOJ计划】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 BZOJ简单题合集x Weblink https://hydro.ac/d/bzoj/p/1590 P ...
最新文章
- 归一化EvoNorms
- python tensorflow 智能家居_TensorFlow平台下的视频目标跟踪深度学习模型设计
- c语言构建栈_选择技术栈构建通用平台
- 关于nunit调试VS2010中的4.0程序集的问题
- leetcode 781. 森林中的兔子(hashmap)
- java,js获取数组最大/小值
- 谷歌浏览器实现直接打印效果
- Mysql安装及其配置
- 60. cache
- NPDP 产品经理国际资格认证
- Offset is outside the bounds of the DataView
- 2018计算机专硕学硕,2018考生快上车!专硕VS学硕,究竟怎么选?
- SAP PP CO02 生产工单修改日志增强
- 「九章」刷屏的背后:万字长文解析,量子计算机和电子计算机各有何优劣?
- 只有两种直播:淘宝直播和其它直播
- element vue 上传模板_Vue Element UI upload 组件上传文件之后 file list 依旧是空数组
- 第三章第七题(金融应用:整钱兑零)(Financial application: monetary units)
- Java黑科技之源:JVMTI完全解读
- 科技H5 | 打破常规H5,QQ-AR开创交互玩法新纪元
- GameFramework食用指南
热门文章
- 圣诞节生成头像微信小程序源码1.3.0
- WordPress插件、Erphp loggedin汉化版插件、 异地IP登录自动禁封用户
- 素材网源码资源下载站源码,带用户中心和VIP充值系统,后台管理+素材下载+积分金币下载
- WPF入门教程系列(一) 创建你的第一个WPF项目
- 无法搜索到电脑模拟热点的可以尝试一下(adhoc补丁)
- 检查xml文件中包含非法xml字符的个数(
- MongoDB 教程五: MongoDB固定集合和性能优化
- Magento批量生成优惠券
- linux系统上传下载命令rz和sz
- 【CVPR2019】论文完整列表一