返回与Trie

时间:2018-04-28 14:36:17

标签: python trie

我设法构建一个Trie,现在我想返回与Trie前缀相匹配的字符串,但是我在编写搜索功能时遇到了问题。

例如,如果我有一个前缀“aa”,我希望将字符串“aa”和“aac”作为输出。

class Node:
    def __init__(self):
        self.children = [None] * 26
        self.end = False
        self.value = ""

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

    def add_word(self, key):
        word_length = len(key)
        current = self.root
        for i in range(word_length):
            position = self.ord_char(key[i])

            if current.children[position] is None:
                current.children[position] = Node()
            current = current.children[position]
            current.value = key[i]
        current.end = True

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

    def prefix_search(self, prefix):
        lst = []
        current = self.root
        prefix_length = len(prefix)
        for c in range(prefix_length):
            c_position = self.ord_char(prefix[c])
            current = current.children[c_position]
            lst.append(current.value)
        #doesnt seem like I'm doing it right

if __name__ == "__main__":
    trie = Trie()
    trie.add_word("aa")
    trie.add_word("aac")
    trie.add_word("b")
    trie.prefix_search("aa")

我正在考虑将字母表连接在一起以通过搜索功能形成最终字符串,但我想不出更好的方法。

2 个答案:

答案 0 :(得分:1)

到目前为止,lst值只是前缀,拆分为单独的字母,但现在您需要处理在children属性中找不到None的每个节点,找到end设置为True的所有节点。每次找到这样的节点时,您都​​有一个完整的单词。任何节点都可以再次拥有多个子节点,分支出更多的单词输出。

您可以使用堆栈来跟踪构建列表需要处理的所有节点以及到目前为止的前缀。使用该节点的前缀将子节点添加到堆栈,并逐个处理这些节点(在执行此操作时向堆栈中添加更多子节点)。

请注意,首先,您不需要构建前缀字符列表,您已将该前缀作为变量。为了达到起点,只需迭代前缀本身就更简单了:

def prefix_search(self, prefix):
    current = self.root
    # get to the starting point
    for c in prefix:
        current = current.children[self.ord_char(c)]
        if current is None:
            # prefix doesn't exist, abort with an empty list
            return []

    found = []
    stack = [(current, prefix)]
    while stack:
        current, prefix = stack.pop()

        if current.end:
            # this is a complete word, named by prefix
            found.append(prefix)

        # add the children to the stack, each with their letter added to the
        # prefix value.
        for child in current.children:
            if child is None:
                continue
            stack.append((child, prefix + child.value))

    return found

对于给定的样本trie和前缀,堆栈从'aa'处的节点开始。第一个while stack:迭代从堆栈中删除该节点,并且因为此节点将end设置为true,所以'aa'被添加到found。该节点只有一个非None子节点,用于c,因此该节点将'aac'添加到堆栈中。

然后while循环重复,发现堆栈中的一个元素看到end已设置,因此'aac'被添加到found,并且不再有子节点位于。堆栈保持空白,while循环结束。

演示:

>>> trie = Trie()
>>> trie.add_word("aa")
>>> trie.add_word("aac")
>>> trie.add_word("b")
>>> trie.prefix_search("aa")
['aa', 'aac']
>>> trie.prefix_search("b")
['b']
>>> trie.add_word('abracadabra')
>>> trie.add_word('abbreviation')
>>> trie.add_word('abbreviated')
>>> trie.add_word('abbrasive')
>>> trie.prefix_search("ab")
['abracadabra', 'abbreviation', 'abbreviated', 'abbrasive']
>>> trie.prefix_search("abr")
['abracadabra']
>>> trie.prefix_search("abb")
['abbreviation', 'abbreviated', 'abbrasive']
>>> trie.prefix_search("abbra")
['abbrasive']

答案 1 :(得分:-5)

.startswith()如何,在我看来,实现搜索的简便方法。