trie树(零)零基础入门

前言:为了一场沙龙水了一篇博客。。。

Trie树简介

(1)【目的】了解多字符串匹配算法Trie树的原理及其应用

(2)【意义】对生活中常见的运用到多字符串匹配的场景有更加深入的了解,比如垃圾邮件的关键字拦截,网络病毒的筛查,文档自动检查等

(3)【内容】

 ①算法引入:基于Trie树的搜索引擎自动联想功能的实现

开源项目网址:https://github.com/wmathor/Search-engine-automatic-association

    Trie树是一种高效的多字符串匹配算法,在利用它进行搜索引擎自动联想时,首先将数据库内的数据都初始化成一颗Trie树,然后根据用户的输入即可进行高效查询。大部分常见的搜索引擎也有该功能,但是同样进行1000次常规查询,Trie树的运行时间明显更短,效率更高。

同时,一些编辑器的自动补全和拼写检查功能也是利用了trie

基于一组预定义的模式构建一个集合,然后,将输入的字符串与该集合内部的字符串进行前缀匹配,进而不断缩小可选范围,在可选范围内将可行字符串输出,进而通过接受状态来显示文本,实现自动补全的功能。当可选的范围为空时,说明该输入的字符串非法,即可报错,也就是实现了拼写自动检查功能。

进而通过以上两个例子引入Trie树。

②前置知识引入

树:如图,仿照现实生活中树的多叉结构,在数据元素的映射关系中,一对多的映射关系就叫做树。

整体形状就是一颗倒过来的大树,原本在底部的根现在到了最上方,而原本最上方的叶子到了最下面。规定每一层的节点是与其直接相连的下一层的节点的父亲节点,相对应的,每一层节点是与其直接相连的上一层节点的儿子节点,特殊地,根节点没有父亲节点。而对于没有儿子节点的节点,我们叫它叶子节点。

树状结构的一个最大特点就是一对多的映射关系,也就是一个节点可以同时管辖多个节点,并且这些节点将唯一地归属于该节点,也就是“每个儿子只能有一个父亲,但是一个父亲可以有多个儿子“。这种关系能够帮助我们更好地处理节点之间的特殊关系。

举个例子,书本的目录,字典的字母,它们的每一个元素之间,就是树的关系。

    一个字符串的前缀:以原字符串第一个字符为起点的一个任意长度(不大于原字符串长度)的字串。比如”Alex”就是”AlexSophia”的一个前缀。

③Trie树基本讲解

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

其核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。缺点:Trie树的内存消耗非常大。当然,或许用左儿子右兄弟的方法建树的话,可能会好点。可见,优化的点存在于建树过程中。

和二叉查找树不同,在Trie树中,每个结点上并非存储一个元素。trie树把要查找的关键词看作一个字符序列,并根据构成关键词字符的先后顺序构造用于检索的树结构。在trie树上进行检索类似于查阅英语词典

先考虑日常生活在字典中查询“zhong”这个拼音的过程。按照之前讲述的关于树的定义,我们不难发现,字典中每一位对应的26个英文字母与上一位的某一个英文字母都是多对一,也就是树的关系。所以我们直接以树的形式展示。

我们肯定是先在26个英文字母中找到z,然后在找到z的前提下,在26个英文字母中找到h,依次类推,最终找到g,我们就确定了“zhong”在字典中的位置了。

    以上就是Trie树的基本查找操作,其与查字典大同小异。为了实现这一步骤,我们首先要把Trie树建立好。

给定一个字符串集:“zhong“,”zhang“,”nihao“,”nihaoa“,然后尝试建立以它们为主要查找对象的Trie树,并判断某一个字符串是否在该字符串集合中出现过

需要注意的是,当字符串集的元素足够多的时候,对于每一个字符串都建立一颗trie树将会非常消耗空间,事实上也没有必要。为了节省空间的开销,我们可以将字符串之间的相同前缀用共同的节点来表示。

如图,对于这颗树上的每一个节点,从根遍历到它的过程就是组成一个单词的过程。其中,对于每一个集合中的字符串,我们还会在它的末尾字符处打上一个标记(红色),这样,我们就能确定每一个字符串的起点和终点了。此时,如果想要查找某一个字符串是否存在的话,只要从根节点出发,依次向下遍历,并查看是否有对应节点即可。到达字符串的最后一个字符时,如果该字符对应的节点被标记过(意味着它是集合中某一个元素的结尾),就代表我们要查找的字符串确实在原集合中。

而当我们查询字符串“zhane“时,

首先从root节点出发,发现第一个节点“Z“是存在的,就向对应方向前进一步。再在Z节点对应的子节点中查找是否存在”H“,发现存在,就继续向对应方向移动。以此类推,前面的“Z“,”H“,”A“,”N“都能在对应路径上找到,但是最后一个要查找的”E“,我们发现它没有与上一个”N“建立联系,所以原来的集合是没有这个字符串的。同理,如果我们查找”zhan“时,最后的字符”N“并没有被标记,所以它事实上也不在原集合中。这就是trie树如何利用字符串的结尾标记和节点间的联系来判断字符串是否存在。

分析该数据结构的时间复杂度。不难发现,对于一个字符串的查询,只要Olen)即可,len是字符串的长度,这是因为我们的Trie树并不会去查询其它无关的信息,而是有方向性地沿一条路查询。而它的建立对应的时间复杂度为O(Σleni),也就是全部字符串的长度之和。总体是一个线性复杂度。如果在一个字符串集合中查找一个长度为5的字符串是否存在,Trie树可以在5次比较中得出结果,而如果用之前的KMP算法去一个一个比对,则需要遍历集合中每一个字符串的前缀,时间复杂度就会大大提高,这也就是Trie树的优越之处。至于它的空间复杂度,最坏情况下每一个字符串的每一个节点都由他独享,则此时空间复杂度为总的字符串长度。

当然,Trie树的建立也不一定非要以英文字母为基本元素,包括数字,汉字等形式的文本,都能用来建立Trie树。

④Trie树的具体应用:

  1. 字符串去重:

100个字符串,有一些是重复的,现在要求去掉重复的部分并保留没有重复的字符串。

只要按顺序建立Trie树并输出即可。

网络平台注册等场景会用到该技术

  1. 词频统计:

问题:给定一个字符串文件,里面有1w个左右的字符串,每一个长度在100左右,问出现频数最高的字符串。

只要在建立Trie树时记录以下每一个节点被经过的次数(如果初次创建,它的经过次数就为1,否则经过次数+1),最后对于每一个终止节点,它唯一对应一个字符串,它被经过的次数就是该字符串出现的次数。所以只要取每一个终止节点对应的最大权值即可。

可以用于大数据分析,网络热词统计等

  1. 字符串公共最长前缀

给定两个字符串,求它们的最长公共前缀。

Trie树利用多个字符串的公共前缀来节省存储空间,反之,当我们把大量字符串存储到一棵Trie树上时,我们可以快速得到某些字符串的公共前缀,那么遍历Trie树时只要某一个节点被经过的次数>1,就说明从它开始就不是公共前缀了。

  1. 字符串排序

给定100个由小写字母组成的名字(alex,bob,Sophia,daisy..),将它们按字典序来排序。(字典序:对于字符串,先按首字符排序,如果首字符相同,再按第二个字符排序,以此类推,如果某一个字符串A是另一个字符串B的前缀,A的字典序<B的字典序)。

按序建好Trie树后,对于每一层节点,从az按字典序向下遍历Trie树即可。

  1. 病毒入侵检测系统:

通过应用字符串算法,可以找到包含与入侵相关的关键字的数据包。将所有的恶意代码都存储在数据库中,并将每个传入的数据与存储的数据利用Trie树来进行比较。如果找到匹配项,则生成警报。

其它:代码查重,垃圾邮件过滤器,生物学信息和DNA测序,数字取证等。

由于时间较短,我们不会过多涉及关于算法的具体实现和代码编写,主要帮助听众理解算法的核心思想及其在生活中的具体应用,对生活现象有更好的理解。

【参考文献】

  1. 数据结构:树 数据结构:树(Tree)【详解】_UniqueUnit的博客-CSDN博客_数据结构 树
  2. Trie树(字典树) 剑指Offer——Trie树(字典树)_No Silver Bullet的博客-CSDN博客_trie树
  3. 字符串匹配算法的应用 字符串匹配算法的应用 - 芒果文档
  4. JSP-AJAX-Trie-实现搜索引擎自动联想 GitHub - wmathor/Search-engine-automatic-association: JSP+AJAX+Trie树实现类似百度搜索的自动联想

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值