原理

先看个例子,存储字符串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为例

]

删除

删除结点,首先查找此字串是否在树中,如果在树中,再查找此结点以下的部分是不是都是只有一个孩子,并且每个结点只有叶子结点是结束结点,如果不是继续往下重复上边过程。

统计字串个数

分两种情况

  1. 计算重复的字串的个数:是结束结点,此时加的是terminabel的个数
  2. 计算不重复的字串的个数:是结束结点,此时加的是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++实现)相关推荐

  1. usaco Cowxor (trie 树)

    没想到trie树还可以用在这上面,厉害厉害. [分析]这是字母树的经典应用.首先因为是求xor的最大值,可以用前缀和计算xor值,然后n^2枚举即可. [cpp] view plaincopy for ...

  2. 字符串匹配算法 -- AC自动机 基于Trie树的高效的敏感词过滤算法

    文章目录 1. 算法背景 2. AC自动机实现原理 2.1 构建失败指针 2.2 依赖失败指针过滤敏感词 3. 复杂度及完整代码 1. 算法背景 之前介绍过单模式串匹配的高效算法:BM和KMP 以及 ...

  3. 字符串匹配数据结构 --Trie树 高效实现搜索词提示 / IDE自动补全

    文章目录 1. 算法背景 2. Trie 树实现原理 2.1 Trie 树的构建 2.2 Trie树的查找 2.3 Trie树的遍历 2.4 Trie树的时间/空间复杂度 2.5 Trie 树 Vs ...

  4. POJ 2418 Hardwood Species(trie 树)

    题目链接 开始想用map的,字典序不会搞,还是老老实实的用trie树把.好久没写了,忘得差不多了. 1 #include <iostream> 2 #include <cstdio& ...

  5. 【bzoj3261】最大异或和 可持久化Trie树

    题目描述 给定一个非负整数序列 {a},初始长度为 N.        有M个操作,有以下两种操作类型: 1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1. 2.Q l r x: ...

  6. 算法 | 动画+解析,轻松理解「Trie树」

    Trie这个名字取自"retrieval",检索,因为Trie可以只用一个前缀便可以在一部字典中找到想要的单词. 虽然发音与「Tree」一致,但为了将这种 字典树 与 普通二叉树 ...

  7. 浅谈树形结构的特性和应用(上):多叉树,红黑树,堆,Trie树,B树,B+树......

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 上篇文章我们主要介绍了线性数据结构,本篇233酱带大家看看 无所不 ...

  8. Trie树合并 + SG函数 ---- BZOJ4730. Alice和Bob又在玩游戏(动态开点Trie 树上全局异或标记 + 合并 + 博弈论)

    题目大题 题目大意: 解题思路: 首先我们对于子树u的SG函数为SG函数为SG函数为 ⨁是异或和\bigoplus是异或和⨁是异或和 SG[u]=mex{⨁w∈(w的父亲在u到v的路径上)SG[w]∣ ...

  9. SZUACM集训字符串基础总结: 字符串最小表示 ,KMP, EXKMP, Manracher, Trie树,字符串的hash; 附带一写常见的运用技巧,邝斌大佬的板子和例题[持续更新]

    第一部分 字符串的匹配<-------->KMP 模式匹配:子串的定位运算称为串的模式匹配或串匹配. 假设有两个串S,T,设S为主串,也称正文串,T为子串,也称为模式,在主串S中查找与模式 ...

  10. BZOJ 1590.Secret Message 秘密信息(Trie树) [Usaco2008 Dec]【BZOJ计划】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 BZOJ简单题合集x Weblink https://hydro.ac/d/bzoj/p/1590 P ...

最新文章

  1. 归一化EvoNorms
  2. python tensorflow 智能家居_TensorFlow平台下的视频目标跟踪深度学习模型设计
  3. c语言构建栈_选择技术栈构建通用平台
  4. 关于nunit调试VS2010中的4.0程序集的问题
  5. leetcode 781. 森林中的兔子(hashmap)
  6. java,js获取数组最大/小值
  7. 谷歌浏览器实现直接打印效果
  8. Mysql安装及其配置
  9. 60. cache
  10. NPDP 产品经理国际资格认证
  11. Offset is outside the bounds of the DataView
  12. 2018计算机专硕学硕,2018考生快上车!专硕VS学硕,究竟怎么选?
  13. SAP PP CO02 生产工单修改日志增强
  14. 「九章」刷屏的背后:万字长文解析,量子计算机和电子计算机各有何优劣?
  15. 只有两种直播:淘宝直播和其它直播
  16. element vue 上传模板_Vue Element UI upload 组件上传文件之后 file list 依旧是空数组
  17. 第三章第七题(金融应用:整钱兑零)(Financial application: monetary units)
  18. Java黑科技之源:JVMTI完全解读
  19. 科技H5 | 打破常规H5,QQ-AR开创交互玩法新纪元
  20. GameFramework食用指南

热门文章

  1. 圣诞节生成头像微信小程序源码1.3.0
  2. WordPress插件、Erphp loggedin汉化版插件、 异地IP登录自动禁封用户
  3. 素材网源码资源下载站源码,带用户中心和VIP充值系统,后台管理+素材下载+积分金币下载
  4. WPF入门教程系列(一) 创建你的第一个WPF项目
  5. 无法搜索到电脑模拟热点的可以尝试一下(adhoc补丁)
  6. 检查xml文件中包含非法xml字符的个数(
  7. MongoDB 教程五: MongoDB固定集合和性能优化
  8. Magento批量生成优惠券
  9. linux系统上传下载命令rz和sz
  10. 【CVPR2019】论文完整列表一