首先说明一点的是,文章里面用的是伪代码,好让各种语言的读者整明白了,我相信最后各位读者自己也可以写出来,最后保险起见。我会贴出个JAVA,python,C++语言版本实现的链接,避免篇幅过长的问题。(博主第一次写数据结构的伪代码,受到C++风格影响比较深,望理解)。
文章目录
1. 字典树究竟是个什么鬼
字典树又名前缀树,Trie树,是一种存储大量字符串的多叉树形数据结构,一个节点存储一个英文字符,一个条路(从根节点到叶子节点的路径)存储了一个单词,整个树先序遍历过后就是一个短句。
下面演示了Happy Hour - incoming(酒桶)这句短句在字典树上的存储方式。
很明显,每条从根节点到叶子节点的路径都构成了单词(不同颜色的圈应该很清晰)。每一个节点下面应该连接子26个节点(26个英文字母),没有节点的数据将属性设置为空罢了。但是这里我没有理由将26个字母全部都标记出来,那不是浪费位置,在搞笑嘛。
如果用对比理解的思想的话,其实这个鬼东西和散列表差不多,只不过散列表是key-value的映射方式,而字典树(Trie树)的key以字符串的形式呈现。散列表的关键字冲突,放在Trie树上就是,一个关键词下面挂着许多小的节点。
1.1 Trie树的特性
Trie树的基本性质可以归纳为:
(1)根节点不包含字符,除根节点以外,每个节点只包含一个字符。
(2)从根节点到某一个节点,路径上经过的字符连接起来,为该所节点对应的字符串。
(3)每个节点的所有子节点包含的字符串不相同。
(4)空间换取时间策略
(5)速度非常快,插入和查询(找一个单词是否存在)的效率很高,均是O(m)
(6)内存空间消耗比较大
2. Trie树的优缺点
Trie树和散列表一样都是利用空间换取时间的一种策略。
优点:
- 插入和查询(找一个单词是否存在)的效率很高,均是O(m),其中 m 是待插入/查询的 字符串长度 。
缺点:
- 如果字母的种数为m,那么树中的每个子节点的出度为m,浪费了许多内存空间,空间换时间可以理解。
3. 字典树的应用(其实都是在存储字符串方面)
1.最典型的例子是搜索引擎:
2.Trie树的进化版本:Merkle Patricia Tree,在区域链里面有许多应用。不过这两个东西博主属实不懂,我不敢乱说贴出两个链接,供了解一下。
CSDN博主虎纠卫的《理解区块链》,
网址:https://blog.csdn.net/csolo/article/details/52858236
CSDN博主qq_33935254的《深入浅出以太坊MPT(Merkle Patricia Tree)》,
网址:https://blog.csdn.net/qq_33935254/article/details/55505472
4. 构建字典树(伪代码)
字典树的常见的操作有插入、查询(删除操作,当然也是比较常见的,但是字典树最主要的功能还是存储字符串和查找单词这一方面),查找前缀。
4.1 初始化字典树,定义字典树的属性
伪代码中的注释可能不是特别清楚,没什么关系我用图。
1. define Trie tree: //定义字典树
2. Property (property,属性的意思): //定义字典树的属性,类似于C++的private,以及C语言的结构
3. Tag isEnd //设置isEnd作为完成一个完整单词的标志,一段路径一个单词
4. Trie* next[26] //子节点A B C ... Z,英文字母不就26个嘛,按26个字母来存储单词
5.
6.
7.
8. Operation: //定义字典树的操作
9. Trie-Initialization ( ) //初始化功能,The Initialize function
10. isEnd = false //一个单词处理完了才把isEnd设置为True,未弄好前isEnd设置为false
11. every-elements-in-the-next = NULL //把next(存储字母的东西)里面每一个元素(26个字母)设置为 NULL(空)
4.2 字典树的插入操作
插入操作的核心思想从根开始,沿着一个单词的各个字母往下走,单词中的一个字母对应的就是树的一个节点,最后单词走完了设置isEnd,表示单词完成。
12.
13.
14. Trie-Insert-Operation ( string word ) //将一个单词(word)插入到字典树里面去
15. node = Trie-root //设置node作为移动节点,首先从根节点往下走
16. for every letters of word //处理一个单词上面的每一个字母
17. if