简介

  字典树:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。

  优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

  性质:   1.  根节点不包含字符,除根节点外每一个节点都只包含一个字符;

      2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;

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

  应用场景:用于统计,排序保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。

      

代码 实现

本文使用链表来实现Trie字典树,字符串的每个字符作为一个Node节点,Node主要有两部分组成:

  1. 是否是单词 (boolean isWord)
  2. 节点所有的子节点,用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字典树的更多相关文章

  1. 算法与数据结构基础 - 字典树(Trie)

    Trie基础 Trie字典树又叫前缀树(prefix tree),用以较快速地进行单词或前缀查询,Trie节点结构如下: //208. Implement Trie (Prefix Tree)clas ...

  2. 算法导论:Trie字典树

    1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tr ...

  3. 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  4. Trie字典树 动态内存

    Trie字典树 #include "stdio.h" #include "iostream" #include "malloc.h" #in ...

  5. 标准Trie字典树学习二:Java实现方式之一

    特别声明: 博文主要是学习过程中的知识整理,以便之后的查阅回顾.部分内容来源于网络(如有摘录未标注请指出).内容如有差错,也欢迎指正! 系列文章: 1. 标准Trie字典树学习一:原理解析 2.标准T ...

  6. 817E. Choosing The Commander trie字典树

    LINK 题意:现有3种操作 加入一个值,删除一个值,询问pi^x<k的个数 思路:很像以前lightoj上写过的01异或的字典树,用字典树维护数求异或值即可 /** @Date : 2017- ...

  7. C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  8. 踹树(Trie 字典树)

    Trie 字典树 ~~ 比 KMP 简单多了,无脑子选手学不会KMP,不会结论题~~ 自己懒得造图了OI WIKI 真棒 字典树大概长这么个亚子 呕吼真棒 就是将读进去的字符串根据当前的字符是什么和所 ...

  9. trie字典树详解及应用

    原文链接    http://www.cnblogs.com/freewater/archive/2012/09/11/2680480.html Trie树详解及其应用   一.知识简介        ...

随机推荐

  1. C++标准库分析总结(七)——<Hashtable、Hash_set、Hash_multiset、unordered容器设计原则>

    编译器对关联容器的实现有两个版本,上一节总结了以红黑树做为基础的实现版本,这一节总结以哈希表(hash table,散列表)为底部结构的实现版本. 一.Hashtable简单介绍 Hashtable相 ...

  2. webpack-merge

    配置分离 随着我们业务逻辑的增多,图片.字体.css.ES6以及CSS预处理器和后处理器逐渐的加入到我们的项目中来,进而导致配置文件的增多,使得配置文件书写起来比较繁琐,更严重者(书写特定文件的位置会 ...

  3. Android Studio如何删除一个Module

    当你想在Android Studio中删除某个module时,大家习惯性的做法都是选中要删除的module,右键去找delete.但是在Android  Studio中你选中module,右键会发现没 ...

  4. java1.8 lambda进行并行运算

    parallelStream()支持并行运算: package com.roocon.thread.t2; import java.util.Arrays; import java.util.List ...

  5. IIS Express(电脑无管理员权限如何启用VS调试)

    转载页面:https://www.cnblogs.com/xbblogs/p/4756552.html(详细版)  直接按照红色字体步骤执行,其他字体可先忽略 出问题再详细看   1.设置配置文件   ...

  6. GO make&new区别

    自:http://www.cnblogs.com/ghj1976/archive/2013/02/12/2910384.html 1.make用于内建类型(map.slice 和channel)的内存 ...

  7. Spring框架中不同类型的事件

    ContextRefreshedEvent,ApplicationContext初始化或者被更新是会触发,ConfigurableApplicationContext接口中的refresh()方法被调 ...

  8. 2018-2019-2 20165312《网络对抗技术》Exp9 Web安全基础

    2018-2019-2 20165312<网络对抗技术>Exp9 Web安全基础 目录 Exp9_1安装Webgoat Exp9_2 SQL注入攻击 Numeric SQL Injecti ...

  9. javasript模块化

    模块概述 随着一个网站越来越大,html页面文件越来越多,由<script src='xxx.js'></script>引入的js文件越来越多,我们的单个js文件很大,上几万行 ...

  10. C语言中的异常处理

    一 前言: 异常处理,对于做面向对象开发的开发者来说是再熟悉不过了,例如在C#中有 try { ... } catch( Exception e){...} finally{ ..... } 在C++ ...