trie树 mysql_Trie树详解(转)

特别声明

本文只是一篇笔记类的文章,所以不存在什么抄袭之类的。

以下为我研究时参考过的链接(有很多,这里我只列出我记得的):

1、字典树的概念

字典树,因为它的搜索快捷的特性被单词搜索系统使用,故又称单词查找树。它是一种树形结构的数据结构。之所以快速,是因为它用空间代替了速度。

2、字典树的特点:

字典树有三个基本性质:

1、根节点不包含字符,除根节点外每一个节点都只包含一个字符

2、从根节点到某一个节点,路径上经过的字符连接起来,就是该节点对应的字符串

3、每个节点的所有子节点包含的字符都不相同。

3、一个包含以下字符串的字典树结构如下图所示:

addadbc

bye

5849b93f58e319bf56e706ff2d08226b.png

Trie树.png

4、字典树的应用场景

1)、字符串的快速查找

给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。

在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。

2)、字典树在“串”排序方面的应用

给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出

用字典树进行排序,采用数组的方式创建字典树,这棵树的每个节点的所有儿子

很显然地按照其字母大小排序,对这棵树进行先序遍历即可。

3)、字典树在最长公共前缀问题的应用

对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的节点的公共祖先个数,于是,问题就转化为最近公共祖先问题。

5、字典树的数据结构

由以上描述我们可以知道,字典树的数据结构如下:

class TrieNode {

char c;

int occurances;

Map children;

}

对以上属性的描述:

1、c, 保存的是该节点的数据,只能是一个字符(注意是一个)

2、occurances, 从单词意思应该知道是发生频率的意思。occurances 是指 当前节点所对应的字符串在字典树里面出现的次数。

3、children, 就是当前节点的子节点,保存的是它的下一个节点的字符。

7、根据字符串常用的功能,字典树类要实现的特性

1)查询是否包含某个字符串

2)查询某个字符串出现的频率

3)插入某个字符串

4)删除某个字符串

5)获取整个字典树的规模,即字典树中包含的不同字符串的个数

基于以上考虑,可以建立一个接口,Trie类只需要实现这个接口即可

8、基于6所描述的特性创建抽象类如下:

public abstract class AbTrie {

// 判断字典树中是否有该字符串。

public abstract boolean contains(String word);

// 返回该字符串在字典树中出现的次数。

public abstract int frequency(String word);

// 插入一个字符串。

public abstract int insert(String word);

// 删除一个字符串。

public abstract boolean remove(String word);

// 整个字典树中不同字符串的个数,也就是保存的不同字符串的个数。

public abstract int size();

}

各个抽象方法的描述已经很详细的解释了,这里不再赘述

9、下面讲解接口中各个方法的实现原理

1)插入字符串

1、从头到尾遍历字符串的每一个字符

2、从根节点开始插入,若该字符存在,那就不用插入新节点,要是不存在,则插入新节点

3、然后顺着插入的节点一直按照上述方法插入剩余的节点

4、为了统计每一个字符串出现的次数,应该在最后一个节点插入后occurances++,表示这个字符串出现的次数增加一次

2)删除一个字符串

1、从root结点的孩子开始(因为每一个字符串的第一个字符肯定在root节点的孩子里),判断该当前节点是否为空,若为空且没有到达所要删除字符串的最后一个字符,则不存在该字符串。若已经到达叶子结点但是并没有遍历完整个字符串,说明整个字符串也不存在,例如要删除的是'harlan1994',而有'harlan'.

2、只有当要删除的字符串找到时并且最后一个字符正好是叶子节点时才需要删除,而且任何删除动作,只能发生在叶子节点。例如要删除'byebye',但是字典里还有'byebyeha',说明byebye不需要删除,只需要更改occurances=0即可标志字典里已经不存在'byebye'这个字符串了

3、当遍历到最后一个字符时,也就是说字典里存在该字符,必须将当前节点的occurances设为0,这样标志着当前节点代表的这个字符串已经不存在了,而要不要删除,需要考虑2中所提到的情况,也就是说,只有删除只发生在叶子节点上。

3)获取字符串出现的次数

1、我们在设计数据结构的时候就有了一个occurances属性

2、只需要判断该字符串是否存在,若存在则返回对应字符下的occurances即可

4)是否存在某个字符串

1、查询字符串是从第一个字符开始的

2、当查询的位置已经超过了字符串的长度,比如要查的是“adc”,但是我们查到树的深度已经超过了c,那么肯定是不存在的

3、如果查询的位置刚好为字符串的长度,这时,就可以判断当前节点的符合要求孩子是否存在,若存在,则字符串存在,否则不存在

4、其余情况则需要继续深入查询,若符合要求的孩子节点存在,则继续查询,否则不存在。

5)整棵Trie树的大小,即不同字符串的个数

1、返回Trie数据结构中的size属性即可。

2、size属性会在insert,remove两个操作后进行更新

10、代码实现

1)插入字符串

int insert(String s, int pos) {

//如果插入空串,则直接返回

//此方法调用时从pos=0开始的递归调用,pos指的是插入的第pos个字符

if (s == null || pos >= s.length())

return 0;

// 如果当前节点没有孩子节点,则new一个

if (children == null)

children = new HashMap();

//创建一个TrieNode

char c = s.charAt(pos);

TrieNode n = children.get(c);

//确保字符保存在即将要插入的节点中

if (n == null) {

n = new TrieNode(c);

children.put(c, n);

}

//插入的结束时直到最后一个字符插入,返回的结果是该字符串出现的次数

//否则继续插入下一个字符

if (pos == s.length() - 1) {

n.occurances++;

return n.occurances;

} else {

return n.insert(s, pos + 1);

}

}

2)删除字符串

boolean remove(String s, int pos) {

if (children == null || s == null)

return false;

//取出第pos个字符,若不存在,则返回false

char c = s.charAt(pos);

TrieNode n = children.get(c);

if (n == null)

return false;

//递归出口是已经到了字符串的最后一个字符,秀嘎occurances=0,代表已经删除了

//否则继续递归到最后一个字符

boolean ret;

if (pos == s.length() - 1) {

int before = n.occurances;

n.occurances = 0;

ret = before > 0;

} else {

ret = n.remove(s, pos + 1);

}

// 1. If we want to remove 'hello', but there is a 'helloa', you do not

// need to remove the saved chars, because its occurances has been

// settled

// 0 witch means the string s no longer exists.

// 2.its occurances must be 0, for exmaple,

// when you want to remove 'harlan1994', but there is no such sequence,

// there is only 'harlan'

// so when we reach the last char 'n',the pos != s.length() - 1, its

// occurances can't be

// settled into 0, and it > 0, so it is not the sequence that need to be

// removed.

// if we just removed a leaf, prune upwards.

//删除之后,必须删除不必要的字符

//比如保存的“Harlan”被删除了,那么如果n保存在叶子节点,意味着它虽然被标记着不存在了,但是还占着空间

//所以必须删除,但是如果“Harlan”删除了,但是Trie里面还保存这“Harlan1994”,那么久不需要删除字符了

if (n.children == null && n.occurances == 0) {

children.remove(n.c);

if (children.size() == 0)

children = null;

}

return ret;

}

3)求一个字符串出现的次数

TrieNode lookup(String s, int pos) {

if (s == null)

return null;

//如果找的次数已经超过了字符的长度,说明,已经递归到超过字符串的深度了,表明字符串不存在

if (pos >= s.length() || children == null)

return null;

//如果刚好到了字符串最后一个,则只需要返回最后一个字符对应的结点,若节点为空,则表明不存在该字符串

else if (pos == s.length() - 1)

return children.get(s.charAt(pos));

//否则继续递归查询下去,直到没有孩子节点了

else {

TrieNode n = children.get(s.charAt(pos));

return n == null ? null : n.lookup(s, pos + 1);

}

}

以上kookup方法返回值是一个TrieNode,要找某个字符串出现的次数,只需要看其中的n.occurances即可。

要看是否包含某个字符串,只需要看是否为空节点即可。

11、下面来一个应用,题目如下:

不考虑字母大小写,在一篇文章中只有英文,不包含其余任何字符,求这篇文章中不同单词的个数。

并求所给单词的出现次数。

1)建立一个测试类Sample,添加两个方法分别求以上两个问题

2)添加一个求取文件内容,并添加字符串到字典树中的方法,关键代码如下:

...

private void init() {

try {

InputStream in = new FileInputStream(new File(

"E:\\Eclipse\\trie\\src\\com\\harlan\\trie\\bible.txt"));

addToDictionary(in);

} catch (Exception e) {

e.printStackTrace();

}

}

public void addToDictionary(InputStream f) throws IOException,

FileNotFoundException {

long t = System.currentTimeMillis();

final int bufSize = 1000;

int read;

int numWords = 0;

InputStreamReader fr = null;

try {

fr = new InputStreamReader(f);

char[] buf = new char[bufSize];

while ((read = fr.read(buf)) != -1) {

// TODO modify this split regex to actually be useful

String[] words = new String(buf, 0, read).split("\\W");

for (String s : words) {

mTrie.insert(s);

numWords++;

}

}

} finally {

if (fr != null) {

try {

fr.close();

} catch (IOException e) {

}

}

}

System.out.println("Read from file and inserted " + numWords

+ " words into trie in " + (System.currentTimeMillis() - t)

/ 1000.0 + " seconds.");

}

public int getSize() {

if (mTrie != null) {

return mTrie.size();

}

return 0;

}

public int getCount(String s) {

return mTrie.frequency(s);

}

测试结果截图如下:

55118e05a7727d9cb8c8803d009b32d5.png

测试.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/525891.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 主键 最佳实践_设计套路:Mysql主键的选取

最近在对一些大表进行优化,发现主键和索引设计都有争议,就此从原理上分析主键设计该如何选取。Mysql的数据结构Mysql是由B树构成,搞清楚下面两个问题,就知道为什么用B树了。1.BTree是为磁盘或者其他直接存取辅助设备而设计的一种平…

java tostring格式化日期_java日期格式化SimpleDateFormat的使用详解

日期和时间格式由 日期和时间模式字符串 指定。在 日期和时间模式字符串 中,未加引号的字母 A 到 Z 和 a 到 z 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 () 引起来,以免进行解释。所有其他字符均不解释&#xff1…

ul 原点显示_CSS+HTML ul li列表原点如何相连

方案一:html参与考试《第一期模拟考试》3小时50分钟学习文档《LDO电路设计规范》3小时50分钟学习文档《LDO电路设计规范》3小时50分钟Css:*{margin:0;padding:0;}ul{margin:100px;padding:0;list-style: none;}ul li{position:relative;padding-left: 30px;padding-bottom: 20p…

java并发执行一个方法_JAVA的执行并发原理

VolatileVolatile关键字用于确保共享数据的可见性与有序性,但是并不能保证方法的原子性,在程序中对Volatile关键字使用得当的话,它比synchronized的使用和执行成本会更低,因为他不会引起线程的上下文切换和调度。先讲一下重排序&a…

java.util. 什么意思_java.util中,util是什么意义

展开全部1. util包的框架常用的集合类主要636f70793231313335323631343130323136353331333431343630实现两个“super接口”而来:Collection和Map。1.1 Collection有两个子接口:List和SetList特点是元素有序,且可重复。实现的常用集合类有Arra…

java测试用例编写_TestNG测试用例编写和执行

编写TestNG用例测试基本上包括以下步骤:编写业务逻辑针对业务逻辑中涉及的方法编写测试类,在代码中插入TestNG的注解直接执行测试类或者添加一个testng.xml文件运行 TestNG.下面我们介绍一个完整的例子来测试一个逻辑类;1.创建一个pojo类Empl…

好爽 java_Intellij是进行scala开发的一个非常好用的工具,可以非常轻松查看scala源码,当然用它来开发Java也是很爽的,之前一直在用scala ide和ec...

Intellij是进行scala开发的一个非常好用的工具,可以非常轻松查看scala源码,当然用它来开发Java也是很爽的,之前一直在用scala ide和eclipse,现在换成intellij简直好用到飞起,但是有些人不知道怎么用intellij去创建一个…

linux服务器安装php7_CentOS 7 下 PHP 7.1.12 安装配置

Linux系统:CentOS 7记录在CentOS 7 下 PHP 7.1.12 安装配置的过程。先安装相关依赖包yum installpcre pcre-devel zlib zlib-devel openssl openssl-devel gd gd-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel e2fsprogs e2fsprogs-dev…

commvault备份mysql,备份MySQL数据库的4种方式

备份MySQL数据库的4种方式前言我们试着想一想, 在生产环境中什么最重要?如果我们服务器的硬件坏了可以维修或者换新, 软件问题可以修复或重新安装,但是如果数据没了呢?这可能是最恐怖的事情了吧, 我感觉在生产环境中应该没有什么比数据跟更为重要.那么我…

php $app-run(),Thinkphp 5.x 应用启动 App::run()

在上文加载完配置等一系列工作之后,进入App::run(),在run()方法中,首先通过自动加载机制拿到 Request 的一个实例接着 $config self::initCommon()初始化公共配置,先是 addNamespace 添加app当前所在的命名空间,然后 …

php react-native,React-Native+Mobx实现商城APP

这次给大家带来React-NativeMobx实现商城APP,React-NativeMobx实现商城APP的注意事项有哪些,下面就是实战案例,一起来看一下。最近一直在学习微信小程序,在学习过程中,看到了 wxapp-mall这个微信小程序的项目&#xff…

matlab axis 用法,MATLAB中regionprops的用法

Matlab图像处理函数:regionprops这里给出在Matlab图像处理工具箱中非常重要的一个图像分析函数:regionprops。顾名思义:它的用途是get the properties of region,即用来度量图像区域属性的函数。语法STATS regionprops(L,propert…

emlog_toolkit.php,emlog 4.0版本IIS6下伪静态划定规矩

emlog默许不能生成静态文件,不过彷佛有生成静态页面的相干插件,该插件博客吧先不研讨,本日博客簿要引见的是emlog 4.0版本在IIS6环境下的伪静态划定规矩,人人都晓得,经由过程伪静态能够让博客文章网址变得对搜索引擎越…

api.php phpcms,phpcms程序api怎么写接口

易站通,带你玩转PHPCMS建站程序,让你更快的熟悉该程序下面让我们来学习吧phpcms api怎么写接口?最近自己开发了一套crm系统,想着如果将来能卖出去,能不能再界面动态调用自己网站的推荐信息,算是一种广告吧&…

oracle 删除表 索引也会删除吗,Oracle 删除当前用户下所有的表、索引、序列

通过下面语句可以得到要删除Oracle的所有表、索引、序列... 的语句select drop table || table_name ||;||chr(13)||chr(10) from user_tables; --delete tablesselect drop view || view_name||;||chr(13)||chr(10) from user_views; --delete viewsselect drop sequence …

基于Java、Kafka、ElasticSearch的搜索框架的设计与实现

Jkes是一个基于Java、Kafka、ElasticSearch的搜索框架。Jkes提供了注解驱动的JPA风格的对象/文档映射,使用rest api用于文档搜索。项目主页:https://github.com/chaokunyang/jkes安装可以参考jkes-integration-test项目快速掌握jkes框架的使用方法。jkes…

Docker是传统的应用发布管理的终结者么?

译者注:使用Docker能真正改善传统的应用发布管理中遇到的问题么?以下是译文:自从2013年发布以来,Docker已经成为每一个操作管理者眼中的最爱。如果你一直与世隔绝,这里恰恰是你错过的部分。Docker是在一个操作环境地址…

基于Mesos/Docker构建数据处理平台

本文深入介绍了去哪儿网利用Mesos和Docker构建私有云服务的全过程,分享了从无状态应用向有状态应用逐步过度的经验与心得。平台概览2014年下半年左右,去哪儿完成了有关构建私有云服务的技术调研,并最终拍定了Docker/Mesos这一方案。下图1展示…

Mesos容器引擎的架构设计和实现解析

引言:提到容器,大家第一时间都会想到Docker,毕竟Docker是目前最为流行的容器开源项目,它实现了一个容器引擎(Docker engine),并且为容器的创建和管理、容器镜像的生成、分发和下载提供一套非常便…

阿里的盔甲、未来20年发展的动力以及对未来的洞察

刚刚变身迈克尔杰克逊,用“经济体”、“理想主义”等词刷屏的马云又在教师节那天,赶到2017世界物联网博览会,为阿里的物联网站台。过去18年以来,淘宝网、天猫、聚划算、全球速卖通、阿里巴巴国际交易市场、1688、阿里妈妈、蚂蚁金…