Ⅰ 前言
大家肯定都用过搜索引擎,应该对下面的情形很熟悉了👇
我们在搜索框输入内容的时候,搜索引擎会根据关键词猜测你要搜的是什么,然后给你提示。这就是一般搜索引擎都有的搜索关键词提示功能。你可以直接从下拉框中选择你要搜索的东西,而不用把所有内容都输入进入,这在一定程度上就节省了我们的时间。并且我们知道,在我们增加或更改输入的内容,下拉框里的提示也会动态地进行变换。
那么,我们天天都在用这个功能,那你是否思考过这个功能是怎么实现的呢?它底层用的是什么数据结构,是什么算法?
像 Google、百度这样的搜索引擎,它们的关键词提示功能非常全面和精准,肯定做了很多优化,但是万变不离其宗,底层最基本的原理都是这篇文章要讲的 Trie 树。
在之前的字符串匹配算法的文章中,我一共讲了四种算法:BF 算法、RK 算法、BM 算法 和 KMP 算法。这四种算法都属于是单模式串匹配算法,就是在一个模式串和一个主串之间进行匹配的算法。
但是 Trie 树这个数据结构对应的是多模式串匹配算法,也就是在一个主串中查找多个模式串。下篇文章要讲的 AC 自动机,就是一个多模式串匹配算法,用的就是 Trie 树结构。
对前面四个单模式串匹配算法还不熟悉的同学可以跳转到我下面的文章中去看👇
【数据结构与算法】->算法->字符串匹配基础(上)->BF 算法 & RK 算法
【数据结构与算法】->算法->字符串匹配基础(中)->BM算法->KMP 三倍性能的强大算法
【数据结构与算法】->算法->字符串匹配基础(下)->KMP 算法
现在我们进入正文。
Ⅱ Trie 树的原理
Trie 树,也叫字典树、单词查找树 。顾名思义,它是一个树形结构,并且是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。
当然,这种问题可以有多种解决方法,比如散列表、红黑树,或者我们上面说的那几个字符串匹配算法,但是,Trie 树在这个问题的解决上有它特有的优点。不仅如此,Trie 树能解决的问题也不限于此,我们慢慢来过。
首先我们先来看看字典树长什么样,我用个简单的例子说明一下。比如有 6 个字符串,分别是 how,hi,her,hello,so,see。我们希望在里面多次查找某个字符串是否存在,如果每次查找,都是拿要查找的字符串跟这 6 个字符串依次进行字符串匹配,那效率就很低,所以有没有更高效的方法呢?
这个时候,我们就可以先对这 6 个字符串做一下预处理,组织成 Trie 树的结构,之后每次查找,都是在 Trie 树中进行匹配查找。Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起。 最后构造出来的就是下图所示的样子👇
其中,根节点不包含任何信息。每个节点表示一个字符串中的字符,从根节点到红色节点的一条路径表示一个字符串。这里有一个需要注意的,就是红色节点并不都是叶子节点。为什么?比如我们要查 se 这个字符串,因为这条分支上已经有了一个红色节点了,所以我们如果要标记 se 的话,e 也必须是红色的,但是它有子节点,不是叶子节点。
为了更容易理解 Trie 树是怎么构造出来的,我用下面这张图来做一个演示构造和分解 Trie 树。构造过程的每一步,都相当于往 Trie 树中插入一个字符串。当所有的字符串都插入完成之后,Trie 树就构造好了。
当我们在 Trie 树中查找一个字符串的时候,比如查找字符串 “her”,那我们将要查找的字符串分割成单个的字符 h,e,r,然后从 Trie 树的根节点开始匹配。如图所示,绿色的路径就是在 Trie 树中匹配的路径。
如果我们要查找的字符串是 “he” 呢?我们还是用上面的方法,从根节点开始,沿着某条路径来匹配。如下图,绿色的路径,就是字符串 “he” 匹配的路径。但是,路径的最后一个节点 “e”,并不是红色的。也就是说,“he” 是某个字符串的前缀子串,但并不能完全匹配任何字符串。
这其实也反映了多模式串匹配,Trie 树中存储的每一条路径都是一个模式串,我们用其他