【问题标题】:Memory Efficient data structure for Trie Implementation用于 Trie 实现的内存高效数据结构
【发布时间】:2015-06-26 08:58:54
【问题描述】:

我正在 python 中实现一个 Trie。到目前为止,我遇到了两种不同的方法来实现它:

1) 使用具有数据成员的类 Node(类似于 C++ 中的 struct Node):

char - 存储字符
is_end - 存储词尾(真或假)
prefix_count - 存储当前前缀的词数

child - 节点类型字典(用于存储其他节点,即 26 个字母)

class Node(object):
    def __init__(self):
        self.char = ''
        self.word = ''
        self.is_end = False
        self.prefix_count = 0
        self.child = {}

2) 使用字典存储所有数据:

例如对于输入words = {'foo', 'bar', 'baz', 'barz'}

我们推导出这个字典:

         {'b': {'a': {'r': {'_end_': '_end_', 'z': {'_end_': '_end_'}},
          'z': {'_end_': '_end_'}}},
          'f': {'o': {'o': {'_end_': '_end_'}}}}

对于大数据集的遍历和其他 trie 操作,哪种是高效且标准的数据结构,既节省内存又快速?

【问题讨论】:

  • 考虑到这是一本字典,你打算如何在self.child 中引用Node 的对象?如果您确实将其保留为dict,并以某种方式引用Node 对象,我认为这两种方法具有相同的时间复杂度,但第一种具有更高的空间复杂度。如果您将self.child 作为列表引用,那么第一个可能会慢一些
  • 感谢您的回复。 Node 中的每个子节点都会有另一个 Node 类型的对象,这将使它成为一个 n 叉树。 @hyades
  • @divyum,如果没有关于你到底想要做什么的具体细节,你只能根据人们的个人喜好来期待意见。该问题的答案讨论了利弊并提供了示例。
  • @divyum 是的,第一个允许您使用更结构化的形式解决繁琐的部分,但同时占用更多空间。如果您谈论的是庞大的数据集,那么您担心的是时间复杂度。无论特里树如何,您都需要遍历 O(len(search_str)) 。上述两种方法都会产生完全相同的结果。

标签: python data-structures tree nlp trie


【解决方案1】:

Trie 在空间复杂度方面是失败的。 Trie 倾向于使用大量内存进行处理和操作。但是为了避免这个问题,有一种称为简洁数据结构的数据结构。尝试在这里实现。

更多信息请参考here

【讨论】:

    【解决方案2】:

    直接替换将嵌套list

    但是 [可以说] 更 Pythonic、内存更紧凑、因此查找速度更快的嵌套 tuple

    当然,更新这样的 trie 变成了 logN,因为您必须重新创建每个祖先节点。不过,如果您的查找比更新频繁得多,那可能还是值得的。

    【讨论】:

      【解决方案3】:

      为什么不两者兼而有之?就在昨天,我正在实现一个类似的数据结构来存储和检索对象的层次结构,并考虑了这种确切的情况。最终使用带有子字典的 Node 对象。 作为对象的主节点允许您使用自定义方法来打印或获取内容,如果需要,您甚至可以进行延迟初始化(您提到了大数据集对吗?)

      class Node(object):
          def __init__(self):
              self.children = collections.defaultdict(lambda:self.__class__())
              self.stuff = ...
          def __str__(self,depth=0):
              if self.children:
                  return str(self.stuff)+'\n'+'\n'.join([' '*depth+k+' ' + v.__str__(depth+1) for k,v in self.children.items()])
              else:
                  return str(self.stuff)
          def get_path(self,path):
              node = self
              while path:
                  node = node.children[path.pop(0)]
              ...
      

      【讨论】:

      • 是的,我提到了大数据集。它显然取决于需求,但我的理由是让它与其他一些功能一起结构化,比如计算前缀、建议单词等……在第一个实现中,我们可以添加更多功能,但在第二个实现中,我们将被绑定到具体的。我想让它更具可扩展性和实时性。
      猜你喜欢
      • 2011-04-30
      • 2020-03-09
      • 2016-03-16
      • 1970-01-01
      • 2017-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多