【问题标题】:Python Trie implementation - Inserting elements into a trie recursivelyPython Trie 实现 - 递归地将元素插入到 trie 中
【发布时间】:2023-02-02 10:04:15
【问题描述】:

我已经使用 Python 中存储单词的列表实现了一个特里树。

我正在尝试编写一个函数,以递归方式将单词插入到 trie 中。

这是我的特里类和函数insert()

class trie :
    def __init__(self, char):
        self.char = char
        self.children = []
    def __repr__ (self):
        return "%s %s" %(self.char, self.children)
    def __str__ (self):
        return "[%s %s]" %(self.char, self.children)

def rest(lst) : 
    return lst.children[-1]

def insert(root, word) :
    if len(word) == 0 :
        return "FIN"
    elif root.char == word[0] :
        return insert(rest(root), word[1:])
    elif root.char != word[0] :
        root.children.append(trie(word[0]))
    return insert(rest(root), word[1:])

问题是 insert() 函数没有将单词插入到正确的子项中。例如 :

t = trie("#") # root
insert(t, "cat")
insert(t, "#card")
insert(t, "#dog")
print(t)

函数 insert() 返回树 [c [a [t [r [d []]]], d [o [g []]]]],但树应该是 [c [a [t []], [r [d []]]], [d [o [g []]]]]。更具体地说,字符“r”和“d”应该在“a”的孩子中。

【问题讨论】:

  • 为儿童集合使用字典会更合适。现在您将不得不在孩子中搜索匹配的字符,这确实会破坏 Trie 可以提供的性能。

标签: python python-3.x recursion trie


【解决方案1】:

如果你找到root.char == word[0],你必须选择正确的下一个孩子,而不是最后一个孩子。因此 rest 函数仅在您创建新的 trie 时有效,但在其他情况下您需要检查所有子项的 char 属性。

下面是一个例子。我迭代地写了它,因为我认为它有点简单:

def insert(root, word):
    cur_root = root
    for ch in word:
        # Check all children to find the one which has the right char attr
        for child in cur_root.children:
            if child.char == ch:
                cur_root = child
                break
        else:
            # Not broken out of the loop, so no child was found with same char
            cur_root.children.append(trie(ch))
            cur_root = rest(cur_root)

【讨论】:

    【解决方案2】:

    您的实施存在一些问题:

    • 它总是在祖父母的最后一个孩子下面添加新节点
    • Trie 应该可以快速访问对应于给定字符的子项。所以它应该是字典而不是列表。或者,如果字符集有限(例如从“a”到“z”),您可以将字母(使用其 ASCII 代码?)映射到列表指数.但是您应该避免迭代列表的需要。
    • Trie 节点不应需要 char 属性。你真的需要早一步那个角色,在你选择那个节点。这就是字典的作用:先按字符选择,然后得到对应的节点。

    这是仅使用 dict 的实现:

    def insert(root, word):
        if not word:
            root["FIN"] = True
        else:
            ch, *word = word
            if ch not in root:
                root[ch] = {} # Create child
            insert(root[ch], word)
    
    def has(root, word):
        if not word:
            return "FIN" in root
        ch, *word = word
        return ch in root and has(root[ch], word)
    
    t = {} # root
    insert(t, "cat")
    insert(t, "card")
    insert(t, "dog")
    print(t)  # {'c': {'a': {'t': {'FIN': True}, 'r': {'d': {'FIN': True}}}}, 'd': {'o': {'g': {'FIN': True}}}}
    
    print(has(t, "ca"))  # False
    print(has(t, "car"))  # False
    print(has(t, "cat"))  # True
    

    【讨论】:

      【解决方案3】:
      class TrieNode:
          def __init__(self):
              # each key is a TrieNode
              self.keys = {}
              self.end = False
      class Trie:
          def __init__(self):
              self.root = TrieNode()
          // I update the node and pass it to the next call
          def insert(self, word: str, node=None) -> None:
              if node == None:
                  node = self.root
              # when you inserted the last char, mark it as end t
              if word == "":
                  node.end = True
                  return
              elif word[0] not in node.keys:
                  node.keys[word[0]] = TrieNode()
                  self.insert(word[1:], node.keys[word[0]])
              # that means key exists
              else:
                  self.insert(word[1:], node.keys[word[0]])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-02
        • 2016-09-13
        • 2020-05-28
        • 1970-01-01
        • 2013-01-01
        • 2020-05-25
        • 1970-01-01
        相关资源
        最近更新 更多