数据结构 -- Trie字典树
简介
字典树:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。
优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
性质: 1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符;
2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
3. 每个节点的所有子节点包含的字符都不相同。
应用场景:用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
代码 实现
本文使用链表来实现Trie字典树,字符串的每个字符作为一个Node节点,Node主要有两部分组成:
- 是否是单词 (boolean isWord)
- 节点所有的子节点,用map来保存 (Map next)
添加
public void add(String word) {
Node current = root;
char[] cs = word.toCharArray();
for (char c : cs) {
Node next = current.next.get(c);
if (next == null) {
//一个字符对应一个Node节点
current.next.put(c, new Node());
}
current = current.next.get(c);
}
//current就是word的最后一个字符的Node //如果当前的node已经是一个word,则不需要添加
if (!current.isWord) {
size++;
current.isWord = true;
}
}
查找
Trie查找操作就比较简单了,遍历带查找的字符串的字符,如果每个节点都存在,并且待查找字符串的最后一个字符对应的Node的 isWord 属性为 true ,则表示该单词存在
public boolean contains(String word) {
Node current = root;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
Node node = current.next.get(c);
if (node == null) {
return false;
}
current = node;
}
//current就是word的最后一个字符的Node
return current.isWord;
}
前缀查询
public boolean containsPrefix(String prefix) {
Node current = root;
for (int i = 0; i < prefix.length(); i++) {
char c = prefix.charAt(i);
Node node = current.next.get(c);
if (node == null) {
return false;
}
current = node;
}
return true;
}
删除
Trie的删除操作就稍微复杂一些,主要分为以下3种情况:
1. 如果单词是另一个单词的前缀
如果待删除的单词是另一个单词的前缀,只需要把该单词的最后一个节点的 isWord 的改成false,比如Trie中存在 panda 和 pan 这两个单词,删除 pan ,只需要把字符 n 对应的节点的 isWord 改成 false 即可。
2. 如果单词的所有字母的都无分支,删除整个单词。
如果单词的所有字母的都没有多个分支(也就是说该单词所有的字符对应的Node都只有一个子节点),则删除整个单词。
3. 如果单词的除了最后一个字母,其他的字母有多个分支
public boolean remove(String word){
Node multiChildNode = null;
int multiChildNodeIndex = -1;
Node current = root;
for (int i = 0; i < word.length(); i++) {
Node child = current.next.get(word.charAt(i));
//如果Trie中没有这个单词
if (child == null) {
return false;
}
//当前节点的子节点大于1个
if (child.next.size() > 1) {
multiChildNodeIndex = i;
multiChildNode = child;
}
current = child;
}
//如果单词后面还有子节点
if (current.next.size() > 0) {
if (current.isWord) {
current.isWord = false;
size--;
return true;
}
//不存在该单词,该单词只是前缀
return false;
}
//如果单词的所有字母的都没有多个分支,删除整个单词
if (multiChildNodeIndex == -1) {
root.next.remove(word.charAt(0));
size--;
return true;
}
//如果单词的除了最后一个字母,其他的字母有分支
if (multiChildNodeIndex != word.length() - 1) {
multiChildNode.next.remove(word.charAt(multiChildNodeIndex + 1));
size--;
return true;
}
return false;
}
Trie查询效率非常高,但是对空间的消耗还是挺大的,这也是典型的空间换时间。
可以使用 压缩字典树(Compressed Trie) ,但是维护相对来说复杂一些。
如果我们不止存储英文单词,还有其他特殊字符,那么维护子节点的集合可能会更多。
可以对Trie字典树做些限制,比如每个节点只能有3个子节点,左边的节点是小于父节点的,中间的节点是等于父节点的,右边的子节点是大于父节点的,这就是三分搜索Trie字典树(Ternary Search Trie)。
参考:https://blog.csdn.net/johnny901114/article/details/80711441
数据结构 -- Trie字典树的更多相关文章
- 算法与数据结构基础 - 字典树(Trie)
Trie基础 Trie字典树又叫前缀树(prefix tree),用以较快速地进行单词或前缀查询,Trie节点结构如下: //208. Implement Trie (Prefix Tree)clas ...
- 算法导论:Trie字典树
1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tr ...
- 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)
萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...
- Trie字典树 动态内存
Trie字典树 #include "stdio.h" #include "iostream" #include "malloc.h" #in ...
- 标准Trie字典树学习二:Java实现方式之一
特别声明: 博文主要是学习过程中的知识整理,以便之后的查阅回顾.部分内容来源于网络(如有摘录未标注请指出).内容如有差错,也欢迎指正! 系列文章: 1. 标准Trie字典树学习一:原理解析 2.标准T ...
- 817E. Choosing The Commander trie字典树
LINK 题意:现有3种操作 加入一个值,删除一个值,询问pi^x<k的个数 思路:很像以前lightoj上写过的01异或的字典树,用字典树维护数求异或值即可 /** @Date : 2017- ...
- C++里创建 Trie字典树(中文词典)(一)(插入、遍历)
萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...
- 踹树(Trie 字典树)
Trie 字典树 ~~ 比 KMP 简单多了,无脑子选手学不会KMP,不会结论题~~ 自己懒得造图了OI WIKI 真棒 字典树大概长这么个亚子 呕吼真棒 就是将读进去的字符串根据当前的字符是什么和所 ...
- trie字典树详解及应用
原文链接 http://www.cnblogs.com/freewater/archive/2012/09/11/2680480.html Trie树详解及其应用 一.知识简介 ...
随机推荐
- luogu_P3674 小清新人渣的本愿
传送门 Solution 莫队,用bitset来存储出现的数 如果是和或者差,直接通过左移右移就可以实现判断 对于积的询问,暴力判就行了,因数只要枚举\(\sqrt n\)个 总复杂度是\(O(n^2 ...
- NOIP1999提高组 题解报告
T1 导弹拦截 题目大意:依次有\(n\) (\(n \le 10^5\))枚导弹,一套导弹拦截系统只能拦截一系列高度递减的导弹(一套系统拦截的弹道不一定相邻).求一套系统最多能拦截多少导弹,以及最少 ...
- Java核心复习——synchronized
一.概念 利用锁机制实现线程同步,synchronized关键字的底层交由了JVM通过C++来实现 Java中的锁有两大特性: 互斥性 同一时间,只允许一个线程持有某个对象锁. 可见性 锁释放前,线程 ...
- idhttp访问DATASNAP有密码验证的中间件
idhttp访问DATASNAP有密码验证的中间件 用TIDHttp访问DataSnap Rest服务器,在服务器采用了用户验证的情况下,客户端需要提交密码,否则不能正常连接. procedure T ...
- OpenJudge计算概论-找和为K的两个元素
/*============================================================== 找和为K的两个元素 总时间限制: 1000ms 内存限制: 65536 ...
- SQL-W3School-函数:SQL NOW() 函数
ylbtech-SQL-W3School-函数:SQL NOW() 函数 1.返回顶部 1. NOW() 函数 NOW 函数返回当前的日期和时间. 提示:如果您在使用 Sql Server 数据库,请 ...
- 123457123456#0#-----com.threeapp.headsoccer----宝宝头球大战
com.threeapp.headsoccer----宝宝头球大战
- 123457---com.threeObj.Baobaoshizi01--- 宝宝识字01
com.threeObj.Baobaoshizi01--- 宝宝识字01
- Block pool ID needed, but service not yet registered with NN java.lang.Exception: trace 异常解决
以上为报错信息: 原因大概为:dd和nd关联的versionId不同导致, 解决方案,备份之前的current文件夹,让其自己生成新的.
- AES加密(java和C#)
需求:Java和C#进行数据交互,互相采用AES/CBC/PKCS5Padding进行加解密 Java加密和解密的代码如下: /** * 加密 1.构造密钥生成器 2.根据 ecnodeRules 规 ...