返回

数据结构:手写字典树(Trie)树探索与应用

后端

简介
字典树又称单词查找树或键树,是一种树形结构,是哈希树的一种变体。典型应用是用于统计和排序大量的字符串(但不限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

原理

字典树是一种多叉树数据结构,用于存储字符串集合。每个节点代表一个字符,根节点是空字符串。如果一个字符串是另一个字符串的前缀,那么这两个字符串在字典树中共享一个公共前缀。

例如,单词“apple”和“banana”共享公共前缀“ap”。因此,在字典树中,这两个单词都存储在同一个节点下。

字典树的查询效率很高,因为只需要沿着字符串的公共前缀在树中搜索一次,就可以找到所有匹配的字符串。

应用

字典树有许多应用,包括:

  • 文本编辑器中的自动完成功能 :当用户在文本编辑器中输入时,字典树可以用来建议可能的单词。
  • 搜索引擎中的拼写检查功能 :当用户在搜索引擎中输入查询时,字典树可以用来检查查询的拼写是否正确。
  • 网络过滤中的垃圾邮件过滤功能 :字典树可以用来过滤垃圾邮件,方法是将垃圾邮件地址存储在字典树中,然后检查传入邮件的地址是否在字典树中。

实现

我们可以使用数组或链表来实现字典树。数组实现比较简单,但是链表实现更加灵活。

数组实现

class TrieNode:
    def __init__(self):
        self.children = [None]*26
        self.isEndOfWord = False

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

    def getNode(self):
        return TrieNode()

    def _charToIndex(self,ch):
        return ord(ch)-ord('a')

    def insert(self,key):
        pCrawl = self.root
        length = len(key)
        for level in range(length):
            index = self._charToIndex(key[level])

            #如果当前字符不在 Trie 节点孩子的列表中,就添加这个字符
            if not pCrawl.children[index]:
                pCrawl.children[index] = self.getNode()
            pCrawl = pCrawl.children[index]

        #标记最后一个字符作为单词的结束
        pCrawl.isEndOfWord = True

    def search(self, key):
        pCrawl = self.root
        length = len(key)
        for level in range(length):
            index = self._charToIndex(key[level])
            if not pCrawl.children[index]:
                return False
            pCrawl = pCrawl.children[index]

        return pCrawl != None and pCrawl.isEndOfWord

# 使用字典树
trie = Trie()
trie.insert("apple")
trie.insert("banana")
print(trie.search("apple"))  # True
print(trie.search("app"))  # False
print(trie.search("banana"))  # True

链表实现

class TrieNode:
    def __init__(self):
        self.children = {}
        self.isEndOfWord = False

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

    def getNode(self):
        return TrieNode()

    def _charToIndex(self,ch):
        return ord(ch)-ord('a')

    def insert(self,key):
        pCrawl = self.root
        length = len(key)
        for level in range(length):
            index = self._charToIndex(key[level])

            #如果当前字符不在 Trie 节点孩子的列表中,就添加这个字符
            if not pCrawl.children.get(index):
                pCrawl.children[index] = self.getNode()
            pCrawl = pCrawl.children[index]

        #标记最后一个字符作为单词的结束
        pCrawl.isEndOfWord = True

    def search(self, key):
        pCrawl = self.root
        length = len(key)
        for level in range(length):
            index = self._charToIndex(key[level])
            if not pCrawl.children.get(index):
                return False
            pCrawl = pCrawl.children[index]

        return pCrawl != None and pCrawl.isEndOfWord

# 使用字典树
trie = Trie()
trie.insert("apple")
trie.insert("banana")
print(trie.search("apple"))  # True
print(trie.search("app"))  # False
print(trie.search("banana"))  # True

总结

字典树是一种非常有用的数据结构,可以用于解决各种问题。它在文本处理和搜索引擎中得到了广泛的应用。