【问题标题】:Trie (Prefix Tree) in PythonPython 中的 Trie(前缀树)
【发布时间】:2009-06-07 01:14:07
【问题描述】:

我不知道这是否是询问算法的地方。但是让我们看看我是否得到任何答案...... :)

如果有什么不清楚的地方,我很乐意澄清。

我刚刚在 python 中实现了一个Trie。然而,有一点似乎比它应该的更复杂(作为一个喜欢简单的人)。也许有人遇到过类似的问题?

我的目标是通过将子树的最大公共前缀存储在其根中来最小化节点数量。例如,如果我们有词 stackoverflowstackbasestackbased,那么树看起来像这样:

              [s]tack
[o]verflow ______/ \_______ [b]ase
                                  \___ [d]

请注意,仍然可以认为边具有一个字符(子节点的第一个字符)。

查找-查询很容易实现。 插入并不难,但比我想要的要复杂一些.. :(

我的想法是一个接一个地插入键(从一个空的 trie 开始),首先搜索要插入的键 k (Find(k)),然后在查找过程停止的地方重新排列/拆分节点。结果有4种情况: (设 k 是我们要插入的键,k' 是节点的键,搜索结束的地方)

  1. k 与 k' 相同
  2. k 是 k' 的“正确”前缀
  3. k' 是 k 的“正确”前缀
  4. k 和 k' 有一些共同的前缀,但没有出现 (1)、(2) 或 (3) 的情况。

似乎每个案例都是独一无二的,因此意味着对 Trie 的不同修改。但是:真的那么复杂吗?我错过了什么吗?有更好的方法吗?

谢谢:)

【问题讨论】:

    标签: python algorithm trie


    【解决方案1】:

    乍一看,听起来您已经实现了Patricia Trie。这种方法在一些文献中也称为路径压缩。应该有该论文的副本不在 ACM 付费墙后面,其中将包括插入算法。

    您可能还想了解另一种压缩方法:级别压缩。路径压缩背后的想法是用具有“跳过”计数的单个超级节点替换单个子节点的字符串。级别压缩背后的想法是用具有“度”计数的超级节点替换完整或几乎完整的子树,该“度”计数表示节点解码的密钥位数。还有第三种方法称为宽度压缩,但我担心我的记忆让我失望,我无法通过快速谷歌搜索找到它的描述。

    级别压缩可以大大缩短平均路径,但是插入和删除算法变得相当复杂,因为它们需要像管理动态数组一样管理 trie 节点。对于正确的数据集,级别压缩树可以快速。据我所知,它们是存储 IP 路由表的第二快的方法,最快的是某种哈希树。

    【讨论】:

    • 美国国家标准与技术研究院网站 (itl.nist.gov/div897/sqg/dads/HTML/patriciatree.html) 上有一些 Patricia 尝试的实现
    • 感谢 Jason 的参考和建议!当它变得密集时,散列也可能是一种很好的技术。但是让我们在插入方面保持简单:)
    【解决方案2】:

    我认为您的方法没有任何问题。如果您正在寻找一个尖峰解决方案,也许情况 4 中采取的措施对于前三种情况实际上是可行的,IE 找到 kk' 的公共前缀并记住这一点重建节点。如果键是彼此的前缀,则生成的 trie 仍然是正确的,只是实现比实际需要做的工作多一点。但是话又说回来,没有任何代码可以查看,很难说这是否适用于您的情况。

    【讨论】:

    • 感谢您的快速回复。第四种情况是如果我们在上面插入“stackbattle”:我们必须创建一个新节点“ba”并在左边和右边放置一个新节点“ttle”,以“base”为根(现在重命名)到“se”)。案例 1-3 完全不同。 (在这些情况下,不必创建 2 个新节点。)
    【解决方案3】:

    有点切线,但如果你非常担心 Trie 中的节点数量,你也可以考虑加入你的单词后缀。我想看看 DAWG(有向无环词图)的想法:http://en.wikipedia.org/wiki/Directed_acyclic_word_graph

    这些的缺点是它们不是很动态,并且创建它们可能很困难。但是,如果您的字典是静态的,它们可以非常紧凑。

    【讨论】:

      【解决方案4】:

      我对您的实施有疑问。您决定拆分字符串以制作前缀树的粒度级别是多少。您可以将堆栈拆分为 s,t,a,c,k 或 st,ta,ac,ck 以及它的许多其他 ngram。大多数前缀树实现都考虑了语言的字母表,基于这个字母表,您可以进行拆分。

      如果您正在为 python 构建前缀树实现,那么您的字母表将是 def、:、if、else... 等

      选择正确的字母表对于构建高效的前缀树有很大的不同。至于您的答案,您可以在 CPAN 上查找 PERL 包,这些包使用 trie 进行最长公共子串计算。你可能会有一些运气,因为它们的大部分实现都非常健壮。

      【讨论】:

      • 我没有使用固定的字母表,以允许所有字符串。我使用哈希表来确定链接是否已经存在。
      【解决方案5】:

      查看:http://www.dalkescientific.com/Python/PyJudy.html 处的 Judy-arrays 和 python 接口

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-12-13
        • 1970-01-01
        • 2011-01-30
        • 2020-01-01
        • 2022-08-20
        • 2010-09-19
        • 1970-01-01
        相关资源
        最近更新 更多