35.Trie树:如何实现搜索引擎的搜索关键词提示功能?

他是如何实现的?底层使用的哪种数据结构和算法?
底层最基本的原理:Trie树
何为Trie树?
又名“字典树”,树形结构。专门处理字符串匹配的数据结构。
解决问题:在一组字符串集合中快速查找某个字符串。
举例:有6个字符串集合:how,hi,her,hello,so,see.在该集合中多次查找某个字符串是否存在。
原始方法:每次查找,待查找的字符串依次与集合中的6个字符串匹配,效率低下。
Trie方法:

本质:利用字符串之间的公共前缀,将重复的前缀合并在一起(兄弟节点按字母顺序插入,先放在左子树)。


查找he,但e节点非叶子节点,是某个字符串的前缀子串,无法匹配(若he位于字符串集合,可在节点里做好标记)。
如何实现Trie树
class Trie(object): def __init__(self): self.root={} self.word_end="" self.list1=list() def insert(self,word): curNode=self.root for c in word: if c not in curNode: curNode[c]={}#一个字符作为键,指向一个空字典 curNode=curNode[c] curNode[self.word_end]=True def search(self,word): curNode = self.root for c in word: if c not in curNode: return False curNode=curNode[c] if self.word_end not in curNode: return False return True def startswith(self,prefix): curNode = self.root for c in prefix: if c not in curNode: return False curNode=curNode[c] return True t = Trie() t.insert("ac") t.insert("a") t.insert("b") print(t.search("wzc")) print(t.startswith("a")) """ 时间复杂度:构建树时,需要扫描所有字符串,O(n)(n为所有字符串长度和);查询时,只需要对比k个节点(k为待查询的字符串的长度),O(k) """
Trie主要有两个操作:1.将字符串构造成Trie树; 2.在Trie树中查询一个字符串
对于多叉树,如何存储一个节点的所有子节点的指针?
下标与字符一一映射,来存储子节点的指针。

class TrieNode { char data; TrieNode children[26];#查找时,通过ASCII码-“a”的ASCII码,迅速找到子节点的指针。 }
若字符仅为26个小写字符,需要26个数组,若字符更多样,占用内存更多;
解决方法:将每个节点的数组换成其他数据结构,比如有序数组、跳表、散列表、红黑树等
举例有序数组:数组中的指针根据所指向的子节点的字符大小顺序排序。查询时,可以二分查找。但插入时,为维护数组中数据的有序性,稍微慢一点。
缩点优化:对仅有一个子节点的节点,而且此节点不是一个串的结束节点,可以将此节点与子节点合并。

Trie与散列表、红黑树的比较
字符串匹配问题本质上就是数据查找问题。支持动态数据高效操作的数据结构:散列表、红黑树、跳表等
在一组字符串中查找字符串,Trie表现欠佳:
- 1.字符串包含的字符集不能太大,存储空间非常大,即使可以优化,也要付出牺牲查询、插入效率的代价;
- 2.要求字符串前缀重合比较多;
- 3.必须从零开始构建Trie,在工程上简单问题复杂化;
- 4.用指针串起来的字符串,对缓存不友好;
工程上,更倾向于散列表或红黑树(编程语言提供现成库)
用武之地:对于精确匹配查找,散列表或红黑树更合适。Trie比较适合的是查找前缀匹配的字符串(搜索关键词的提示功能)。
解答开题
假设关键词库由用户的热门搜索关键词组成,构造Trie树。当输入某个词时,把这个词作为一个前缀子串在Trie中匹配。
Trie树的扩展运用:自动补全(代码编辑器自动补全、输入法自动补全等)
小结
对内存不敏感或内存消耗在可接受范围的,Trie的字符串匹配还是十分高效的
浙公网安备 33010602011771号