http://chenyufei.info/blog/2008-04-18/ternary-search-tree/comment-page-1/

http://en.wikipedia.org/wiki/Ternary_search_tree

http://www.ddj.com/windows/184410528

http://www.itl.nist.gov/div897/sqg/dads/HTML/ternarySearchTree.html

今天谈下技术。介绍一个蛮有趣的数据结构 Ternary Search Tree,我毕设里的关键代码就依赖于这个数据结构。

这个数据结构的思路 1960 年左右就有了,不过其实际使用价值一直被忽略了。Jon Bentley 和 Robert Sedgewick 在 1997 年发表的论文 Fast Algorithms for Sorting and Searching Strings 中利用这个数据结构实现了针对字符串的快速排序和查找算法,网页上除了论文以外还有实现和测试代码。后来他们又专门针对 Ternary Search Tree 发表了一篇文章,Dr. Dobb 上有在线版本 。 我是在 Robert Sedgewick 的《Algorithms in C, 3rd edition》中 Radix Search Tree 这一章看到这个数据结构的,这本书将 multi-way branching tries 和 TST 放在一起进行介绍,把 TST 作为 multi-way branching tries 的另一种表现形式来看待,另外也将 TST 和 digital search tries 进行了比较。这里只是对这个数据结构进行概述,详细内容还是看作者的论文去。

Ternary Search Tree 的主要应用场景如下:字符串作为 key,每个字符串的长度不定,需要一种支持动态集合操作的数据结构以便能够快速的通过 key 查找到其对应的 value。用 hash table 的话可以做到快速的搜索,但是有两个缺点,一是随着保存的字符串的增多,需要重新构建 hash table 以保证快速的查找,二是 hash table 中不维护 key 之间的顺序关系。使用平衡 Binary Search Tree (BST) 两个问题都能解决,但是查找的速度相对 hash table 变慢了。如果使用 digital search trie 的话查找虽然非常快,但是需要的内存空间太大。

Ternary Search Tree 结合了 BST 和 trie 两者的优点,利用它还可以很容易的实现 partial-match searching, near-neighbor searching 这样的字符串搜索操作。而且 TST 本身非常简单,实现起来也很容易。与 BST 相比,TST 中每个节点存放的不是整个 key,而只是 key 中的一个字符。而对 tries,只需要进行一点小的修改就得到了 TST。(用 trie 描述起来比较方便,如果不知道 tries 的话可以先看下 trie 是什么 。)

  1. 把 tries 中的每个节点保存的 bit 换成一个字符
  2. 和 tries 一样,数据都保存在叶子节点
  3. tries 中每个节点最多有两个子节点,TST 有三个,分别称为 left, mid, right

插入 key 的时候,从树根作为当前节点开始(树为空的时候树根为 nil),一个字符一个字符的递归执行下面过程。

  1. 如果当前节点为 nil,则创建一个新的节点,将当前字符保存在节点中,将其设置为当前节点。
  2. 如果当前字符和当前节点保存的字符都为 ‘/0′,将数据存于当前节点,终止调用。
  3. 如果当前字符小于当前节点保存的字符,那么递归将当前字符 插入节点的 left 子节点,大于则插入 right 子节点;相等则将下一个字符 插入当前节点的 mid 子节点。

搜索的过程和插入类似,把 key 一个字符一个字符的和树中节点保存的字符进行比较,同样从树根开始递归执行。

  1. 如果当前节点为 nil,则查找失败。
  2. 如果当前字符比节点中的小,递归对 left 子节点查找,依然比较当前字符。
  3. 如果当前字符比节点中的大,递归对 right 子节点查找,依然比较当前字符。
  4. 如果当前字符与节点中的相等且都为 ‘/0′,则这个节点中就存着 key 对应的 value,终止调用。如果相等但是不是 ‘/0′,则递归对 mid 子节点查找,比较字符为下一个字符。

对 TST 性能的最坏情况分析在 “The Analysis of Hybrid Trie Structures” 这篇论文中,不过这篇论文下不到。对失败的查找,字符比较次数往往远小于其中包含的字符个数。使用 hash table 的话仅计算 hash 值就需要访问 key 中的所有字符(比如这里的 string hashing function ),而且得到 hash value 之后还得检查 search key 与实际保存的 key 是否相等。所以 TST 的不成功的搜索比 hash table 更快。

论文的两位作者提供的 C 源代码里给出了迭代的插入和搜索的实现。对插入还作了优化,通过预先分配内存池的办法避免了内存分配成为性能瓶颈。对于数据的保存使用了一点 hack,通过 type cast 直接用叶节点的 mid 指针保存 value。因为 char 默认为 unsigned (至少 gcc 如此),所以保存 ‘/0′ 的节点的 mid 和 left 肯定不会指向节点(right 节点可能指向树的节点),所以可以利用他们来保存 value。示例代码直接将 key 保存在叶节点中,但实际上 key 保不保存都没关系,除非以后要用到。对示例代码还有一点要说明的是递归版本和迭代版本有一点小差别,递归版本在实现遇到相同的 key 的时候会将新 value 的存入,而迭代的版本则不会。

对于 partial-match search, near-neighbor search 我就不罗嗦了,论文作者肯定比我说的清楚多了。我毕设里面使用的 search 也是标准 search 的一个小变种。我的 TST 中的 key 是文件系统的路径(假设文件系统用 UTF-8 编码,所以树的节点存放 char 就 OK 了),给定一个 search key (path),如果 TST 中存有 search path 的祖先目录,我希望能够找到与之距离最近的祖先目录。用 TST 来实现这个操作也是非常容易的,有兴趣的可以自己想一下 :-)

TST 也有可以改进的地方。插入过程中,往往到了末尾的字符的时候树种的每一个节点都只有一个 mid 字节点,也就是所谓的 one-way branching,这导致了使用多余的空间,而且对于成功的搜索速度也不一定是最优的。一种改进办法是在接近字符串的尾部使用 multi-way branching 来减少需要的 node,不过怎样确定在什么地方开始 multi-way branching 比较麻烦,而且还要处理多种节点类型的情况。另一种方法是使用 PATRICIA 的思想,在每个节点上再存一个索引,表示其存放的字符是 key 中的第几个字符,比较的时候直接将其与 key 中的特定字符进行比较而不是一个一个的往下比较。这样一来减少了使用的节点,二来对成功的查找,如果保存着的两个 key 之间有几个连续的相同字符就可以跳过这些字符,直接跳到能够区分出这两个不同字符串的字符位置。但这样要求树中也保存 key,在找到节点之后还不要比较一下 search key 和 TST 中保存的 key 是否相同才能决定是否是成功的查找。

发现描述数据结构算法之类的东西还是挺麻烦的,看别人的文章的时候不觉得,自己写的时候就发现难了,也不知道写的能不能让人明白了。欢迎提出建议 :-)

Ternary Search Tree(三叉树)相关推荐

  1. 快乐学算法之:三分查找树ternary search tree

    文章目录 简介 三分查找树的结构 三分查找树的代码表示 三分查找树的应用 简介 之前我们介绍了tire字典树,tire字典树的优点就是插入和查找比较快速,但是它的缺点就是占用的空间比较大.假如我们要存 ...

  2. python实现三叉树_使用python代码实现三叉搜索树高效率”自动输入提示”功能

    最近项目中需要通过全拼音和简写拼音实现输入自动提示结果功能,查了一些资料发现三叉搜索树无论是在时间还是空间上都比较优秀. 三叉搜索树是trie树的演化版,除去了指针,这样在空间上节省不少,每个节点基本 ...

  3. Ternary Search Trees 三分树

    Efficient auto-complete with a ternary search tree 分类: 算法和数据结构学习 2012-04-18 18:03  125人阅读  评论(0)  收藏 ...

  4. Tries and Ternary Search Trees in Python and Javascript

    http://jeethurao.com/blog/?p=146 woadwarrior / trie / overview - Bitbucket Using redis A Mochikit st ...

  5. 自己理解三叉树TernarySearchTrie

    花了差不多一天半的时间终于把一颗三叉树看完了,不过对于里面还有点疑惑,下面在代码里注释上了自己的理解,里面还存在一些疑问,欢迎理解的朋友们指出其中的错误,以及解答里面的疑问. package org. ...

  6. 笔试算法题(58):二分查找树性能分析(Binary Search Tree Performance Analysis)

    议题:二分查找树性能分析(Binary Search Tree Performance Analysis) 分析: 二叉搜索树(Binary Search Tree,BST)是一颗典型的二叉树,同时任 ...

  7. 【ACM】二叉搜索树(Binary Search Tree /BS Tree) 小结

    动态管理集合的数据结构--二叉搜索树 搜索树是一种可以进行插入,搜索,删除等操作的数据结构,可以用字典或者优先队列. 二叉排序树又称为二叉查找树,他或者为空树,或者是满足如下性质的二叉树. (1)若它 ...

  8. 二叉查找树(binary search tree)详解

    二叉查找树(Binary Search Tree),也称二叉排序树(binary sorted tree),是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有结点的值均小于 ...

  9. 【LeetCode-面试算法经典-Java实现】【109-Convert Sorted List to Binary Search Tree(排序链表转换成二叉排序树)】...

    [109-Convert Sorted List to Binary Search Tree(排序链表转换成二叉排序树)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 ...

最新文章

  1. python使用fpdf的multi_cell API实现长文本写入的自动换行功能实战
  2. 这个AI模型用最少的训练数据学习对象之间的关系
  3. elasticsearch实现按天翻滚索引
  4. 计算机算法设计与分析二--分治
  5. linux iscsi
  6. setTimeOut与 setInterval区别
  7. VirtualBox 虚拟机转换为KVM虚拟机
  8. FTP用户无法登陆排错详解
  9. Camtasia Recorder 2020如何确定录制区域
  10. MacOS上禁用自动启动Adobe Creative Cloud
  11. Http权威指南笔记(三)——HTTP报文
  12. 概率论与数理统计(3)--指数分布函数及其期望、方差
  13. linux mariadb 升级,Mariadb数据库更新
  14. 计算机深度休眠以后怎么唤醒,电脑进入深度睡眠,肿么唤醒?
  15. 数据中台与数据湖概念认知
  16. 【字节跳动】 https://job.bytedance.com/campus 内推码:MZ9BJHD 电话:13855119574 邮箱:yinxiang.stephen@bytedance.com
  17. 常见端口扫描原理总结
  18. Runtime error: expected scalar type Float but found Double
  19. 超级计算机 任务提交,超算任务提交系统slurm用法
  20. Opencv——视频跳帧处理

热门文章

  1. 【简陋Web应用3】实现人脸比对
  2. 乐高机器人亮剑_全球机器人从化“亮剑”
  3. Uniapp返回上一页触发页面更新
  4. Switchport详细用法
  5. MySQL的下载与安装教程--超详细
  6. vue兼容IE 360
  7. fa常用脚本,资产类表的字段详解
  8. oracle rebuild online,rebuild online 请慎用
  9. python模拟手机按键_Appium+Python-模拟手机按键操作
  10. Lsyncd:负载均衡之后,服务器的文件双向同步