数据结构 -- 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树详解及其应用 一.知识简介 ...
随机推荐
- mac apache 管理
sudo apachectl start sudo apachectl stop sudo apachectl restart
- P3180 [HAOI2016]地图
P3180 [HAOI2016]地图 显然,这是一个仙人掌图 inline void tarjan(LL u,LL fa){ low[u]=dfn[u]=++tot, pre[tot]=u; for( ...
- 学号 20175313 《Android程序设计》实验报告
目录 一.实验内容 (1)Android Stuidio的安装测试 (2)Activity测试 (3)UI测试 (4)布局测试 (5)事件处理测试 二.实验步骤 (1)Android Stuidio的 ...
- oracle之nvl,nvl2,decode
oracle sql常用查询nvl,nvl2,decode区别及使用方法 1,NVL( E1, E2) 如果E1为NULL,则NVL函数返回E2的值,否则返回E1的值,如果两个参数都为NULL ,则返 ...
- android DownloadManager: java.lang.IllegalArgumentException: Not a file URI: content://
DownloadManager 使用Uri指定下载路径Bug 使用DownloadManager 下载文件 通常写法: DownloadManager dm = (DownloadManager) g ...
- Vue项目中的http请求统一管理
module.exports = { dev: { // Paths assetsSubDirectory: '/', assetsPublicPath: '/', proxyTable: { /op ...
- [webpack]深入理解proxy代理
1.一个基本的代理 module.exports = { //... devServer: { proxy: { '/api': 'http://localhost:3000' } } }; /api ...
- Angular 中的生命周期函数
一. Angular中的生命周期函数 官方文档:https://www.angular.cn/guide/lifecycle-hooks 生命周期函数通俗的讲就是组件创建.组件更新.组件销毁的时候会触 ...
- 简易的CRM系统案例之Struts2+JSP+MySQL版本
对简易的CRM系统案例之Servlet+Jsp+MySQL版本改进 Servlet优化为Struts2 学习 <?xml version="1.0" encoding=&qu ...
- javascript中的Error对象
在javascript中一旦代码解析或运行时发生错误,javascript引擎就会自动产生并抛出一个Error对象的实例,然后整个程序就中断在发生错误的地方. Error对象的实例有三个基本的属性: ...