【问题标题】:Issue searching through a Trie通过 Trie 搜索问题
【发布时间】:2018-05-01 07:57:15
【问题描述】:

我编写了一个实现 Trie 数据结构的代码,它接收字符串列表和字符串的计数。

lst = [['james',9],['chloe',20],['chlara',30]]

字符串是名称,后面的整数值是计数。一旦构建了 trie,它就会提示用户输入前缀,

userinput = ch

这样,代码将返回字符串 chlara,因为它与具有前缀 ch 的 chloe 相比具有更高的计数。我已经成功构建了 Trie,但我在搜索功能方面遇到了困难。

class Node:
    def __init__(self):
        self.children = [None] * 26
        self.end = False
        self.frequency = 0
        self.goindex = 0
        self.index = 0

class Trie:
    def __init__(self):
        self.root = Node()

    def ord_char(self,key):
        ord_rep = ord(key) - ord('a')
        return ord_rep

    def add_word(self,lst):
        word = lst[0]    #word
        freq = lst[1]    #frequency of string

        word_len = len(word)    

        current = self.root    #start from root node

        for i in range(word_len):
            position = self.ord_char(word[i])

            if current.children[position] is None:
                current.children[position] = Node()

            current = current.children[position]

            if current.frequency > freq:
                continue
            else:
                current.frequency = freq
            current.index = position

        current.end = True  #end of string


def main():
    trie = Trie()

    for i in list2:
        trie.add_word(i)
    user = input("Enter a prefix: ")
    print(trie.prefix_search(user))

if __name__ == "__main__":
    main()

我收到了不完整的字符串“chla”,我很确定这是因为我的搜索功能效率低下且无法正常工作。

更新

我现在面临的问题是,如果我的前缀是“aberr”,我将返回“aberration”而不是“aberr”

【问题讨论】:

    标签: python trie


    【解决方案1】:

    你永远不会正确地遍历你的 trie。您有两个嵌套的 for 循环,因此只从您的前缀中遍历两个节点(字符)。

    我将假设您想要返回 一个 结果,即使有多个字符串具有匹配的后缀和匹配的计数。

    使用while 循环,并继续遵循最高的count 值,直到您到达一个没有更多子节点且其值等于当前节点计数的节点。请确认您的 end 对于该节点为 True,因为这表明您的单词添加代码中存在错误:

    def prefix_search(self, prefix):
        # traverse the prefix
        current = self.root
        for c in prefix:
            current = current.children[self.ord_char(c)]
            if current is None:
                return None  # None is a much better return value than -1
    
        while current is not None:
            for child in current.children:
                if child is None:
                    continue
                if child.count == current.count:
                    # found first child with same score, continue from here
                    prefix += chr(child.index + 97)
                    current = child
                    break
            else:
                # no children with equal score, this is the longest match
                assert current.end, "Data structure inconsistent"
                return prefix
    

    演示:

    >>> trie.prefix_search('ch')
    'chlara'
    >>> trie.prefix_search('j')
    'james'
    

    还有一些极端情况:

    >>> trie.add_word(('chlarissa', 9))  # longer word, lower count!
    >>> trie.prefix_search('ch')
    'chlara'
    >>> trie.add_word(('janet', 6))  # same length and score as james, won't be found
    >>> trie.prefix_search('j')
    'james'
    

    如果数据结构有错误;这故意设置了错误的计数:

    >>> trie.root.children[9].children[0].count = 7  # 'ja', 7, so higher, but not an end node
    >>> trie.prefix_search('j')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<string>", line 59, in prefix_search
    AssertionError: Data structure inconsistent
    

    【讨论】:

    • @MartihnPieters 是的,返回一个结果是我正在寻找的。看看 while 循环是如何流动的,与我尝试过的相比,我对它的简化程度感到非常震惊。傻我!最后的断言绝对精彩!非常感谢您的参与。非常感谢。
    • 想一想,如果不是遍历所有由'for child in current.children'表示的子节点,我们可以知道下一个包含最高的子节点在哪里更好频率串在一瞬间?我已经在存储最高频率节点的下一个索引的节点中实现了一个“go index”属性,并尝试在 add_word 函数中实现它。很想给它一些建议。
    • @clink:当然,这也可以,只是要小心边缘情况,例如存在具有相同前缀但分数较低的较长单词。不过,遍历 26 个项目并不昂贵。
    • 请原谅我的提问,但是,是的,我确实遇到了边缘情况的问题。我可以就 add_word 函数中的上述编辑代码寻求一些帮助吗?好像我没有正确处理 go 索引
    • 在上面编辑过的代码中,如果我输入频率为 8765 的输入“aberr”和频率为 900 的输入“aberration”,程序会在边缘情况下失败,当我输入'aberr' 的前缀。我完全迷路了。
    猜你喜欢
    • 2014-03-29
    • 2014-06-30
    • 2012-03-19
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多