- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
后缀树的构造方法-Ukkonen 详解
问题的来源
字符串匹配问题是程序员经常要面对的问题. 字符串匹配算法的改进可以使许多工程
受益良多, 比如数据压缩和DNA 排列. 这篇文章讨论的是一种相对鲜为人知的数据结
构 后缀树, 并介绍它是如何通过自身的特性去解决一些复杂的匹配问题.
你可以把自己想象成一名工作于DNA 排列工程的程序员. 那些基因研究者们天天忙着
分切病毒的基因材料, 制造出一段一段的核苷酸序列. 他们把这些序列发到你的服务
器里, 指望你在基因数据库中定位. 要知道, 你的数据库里有数百种病毒的数据,
而一个特定的病毒可以有成千上万的碱基. 你的程序必须像C/S 工程那样实时向博士
们反馈信息, 这需要一个很好的方案.
很明显, 在这个问题上采取暴力算法是极其低效的. 这种方法需要你在基因数据库里
对比每一个核苷酸, 测试一个较长的基因段基本会把你的C/S 系统变成一台古老的批
处理机.
直觉上的解决方法
由于基因数据库一般是不变的, 通过预处理来把搜索简化或许是个好主意. 一种预处
理的方法是建立一棵Trie. 我们通过Trie 引申出一种东西叫作后缀Trie. (后缀
Trie 离后缀树仅一步之遥.) 首先, Trie是一种n 叉树, n 为字母表大小, 每个
节点表示从根节点到此节点所经过的所有字符组成的字符串. 而后缀 Trie 的 “后缀”
说明这棵Trie 包含了所给字段的所有后缀 (也许正是一个病毒基因).
图1
BANANAS 的后缀Trie
图1 展示了文本BANANAS 的后缀Trie. 关于这棵Trie 有两个地方需要注意. 第
一, 从根节点开始, BANANAS 的每一个后缀都插入到Trie 中, 包括BANANAS,
ANANAS, NANAS, ANAS, NAS, AS, S. 第二, 鉴于这种结构, 你可以通过从根
节点往下匹配的方式搜索到单词的任何一个子串.
这里所说的第二点正是我们认为后缀Trie 优秀的原因. 如果你输入一个长度为N 的
文本并想在其中搜索一个长度为M 的串, 传统的暴力匹配需要进行N*M 次字符对比,
而一些改进过的匹配技术, 比如像Boyer-Moore 算法, 可以在O(N+M)的时间开销
内解决问题, 平均效率更是令人满意. 然而, 后缀Trie 亮出了O(M)的牌子, 彻底
鄙视了其他算法的成绩, 后缀Trie 对比的次数仅仅相当于被搜索串的长度!
这确实是可圈可点的威力, 这意味着你能通过仅仅7 次对比便在莎士比亚所有作品中
找出BANANAS. 但有一点我们可不能忘了, 构造后缀Trie 也是需要时间的.
后缀Trie 之所以没有家喻户晓正是因为构造它需要O(n2)的时间和空间. 平方级的
开销使它在最需要它的领域 长串搜索 中被拒之门外.
横空出世
直到1976 年, Edward McCreigh 发表了一篇论文, 咱们的后缀树问世了. 后缀
Trie 的困境被彻底打破.
后缀树跟后缀Trie 有着一样的布局, 但它把只有一个儿子的节点给剔除了. 这个过
程被称为路径压缩, 这意味着树上的某些边将表示一个序列而不是单独的字符.
图2
BANANAS 的后缀树
图2 是由图1 的后缀Trie 转化而来的后缀树. 你会发现这树基本还是那个形状, 只
是节点变少了. 在剔除了只有一个儿子的节点之后, 总节点数由23 降为11. 经过
证明, 在最坏情况下, 后缀树的节点数也不会超过2N (N 为文本的长度). 这使构造
后缀树的线性时空开销成为可能.
然而, McCreight 最初的构造法是有些缺陷的, 原则上它要按逆序构造, 也就是说
字符要从末端开始插入. 如此一来, 便不能作为在线算法, 它变得更加难以应用于实
际问题, 如数据压缩.
20 年后, 来自赫尔辛基理工大学的Esko Ukkonen 把原算法作了一些改动, 把它变
成了从左往右. 本文接下来的所有描述和代码都是基于Esko Ukkonen 的成果.
对于所给的文本T, Esko Ukkonen 的算法是由一棵空树开始, 逐步构造T 的每个
前缀的后缀树. 比如我们构造BANANAS 的后缀树, 先由B 开始, 接着是BA, 然后
BAN, … . 不断更新直到构造出BANANAS 的后缀树.
图3
逐步构造后缀树
初窥门径
加入一个新的前缀需要访问树中已有的后缀. 我们从最长的一个后缀开始(图3 中的
BAN), 一直访问到最短的后缀(空后缀). 每个后缀会在以下三种节点的其中一种结
束.
l 一个叶节点. 这个是常识了, 图4
文档评论(0)