字典树(java实现)

一、概念:

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

Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

二、3个基本性质:

1.根节点不包含字符,除根节点外每一个节点都只包含一个字符。
    2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
    3.每个节点的所有子节点包含的字符都不相同。

三、Trie树的构建

本质上,Trie是一颗存储多个字符串的树。相邻节点间的边代表一个字符,这样树的每条分支代表一则子串,而树的叶节点则代表完整的字符串。和普通树不同的地方是,相同的字符串前缀共享同一条分支。举一个例子。给出一组单词,inn, int, at, age, adv, ant, 我们可以得到下面的Trie:

    搭建Trie的基本算法很简单,无非是逐一把每则单词的每个字母插入Trie。插入前先看前缀是否存在。如果存在,就共享,否则创建对应的节点和边。比如要插入单词add,就有下面几步:
    1.考察前缀"a",发现边a已经存在。于是顺着边a走到节点a。
    2.考察剩下的字符串"dd"的前缀"d",发现从节点a出发,已经有边d存在。于是顺着边d走到节点ad
    3.考察最后一个字符"d",这下从节点ad出发没有边d了,于是创建节点ad的子节点add,并把边ad->add标记为d。

插入:

插入操作就是将单词的每个字母都逐一插入Trie树,插入前看这个字母对应的节点是否存在,若不存在就新建一个节点,否则就共享那一个节点,还是以下图为例:

假如说我们要在原Trie树中新插入一个单词and,那我们的操作为:

  1. 插入第一个字母a,发现根节点存在子节点a,则共享节点a
  2. 插入第二个字母n,发现节点a不存在子节点n,则新建子节点n
  3. 插入第三个字母d,发现节点n不存在子节点d,则新建子节点d

查询:

查询操作和插入操作其实差不多,就是在Trie树中找这个单词的每个字母,若找到了就继续找下去,若没有找到就可以直接退出了,因为若没找到就说明没有这个单词,还还还是以下图为例:

【复杂度分析】

Trie树其实是一种用空间换时间的算法,前面也提到过,它占用的空间一般很大,但时间是非常高效的,插入和查询的时间复杂度都是O(l)的,总体来说还是很优秀的

import java.util.HashMap;
public class Trie_Tree{/*** 内部节点类* @author "zhshl"* @date   2014-10-14**/private class Node{private int dumpli_num;该字串的重复数目,  该属性统计重复次数的时候有用,取值为0、1、2、3、4、5……private int prefix_num;///以该字串为前缀的字串数, 应该包括该字串本身!!!!!private Node childs[];此处用数组实现,当然也可以map或list实现以节省空间private boolean isLeaf;///是否为单词节点public Node(){dumpli_num=0;prefix_num=0;isLeaf=false;childs=new Node[26];}}private Node root;///树根public Trie_Tree(){///初始化trie 树root=new Node();}/*** 插入字串,用循环代替迭代实现* @param words*/public void insert(String words){insert(this.root, words);}/*** 插入字串,用循环代替迭代实现* @param root* @param words*/private void insert(Node root,String words){words=words.toLowerCase();转化为小写char[] chrs=words.toCharArray();for(int i=0,length=chrs.length; i<length; i++){///用相对于a字母的值作为下标索引,也隐式地记录了该字母的值int index=chrs[i]-'a';if(root.childs[index]!=null){已经存在了,该子节点prefix_num++root.childs[index].prefix_num++;}else{///如果不存在root.childs[index]=new Node();root.childs[index].prefix_num++;}///如果到了字串结尾,则做标记if(i==length-1){root.childs[index].isLeaf=true;root.childs[index].dumpli_num++;}///root指向子节点,继续处理root=root.childs[index];}}/*** 遍历Trie树,查找所有的words以及出现次数* @return HashMap<String, Integer> map*/public HashMap<String,Integer> getAllWords(){return preTraversal(this.root, "");}/*** 前序遍历。。。* @param root       子树根节点* @param prefixs  查询到该节点前所遍历过的前缀* @return*/private  HashMap<String,Integer> preTraversal(Node root,String prefixs){HashMap<String, Integer> map=new HashMap<>();if(root!=null){if(root.isLeaf==true){当前即为一个单词map.put(prefixs, root.dumpli_num);}for(int i=0,length=root.childs.length; i<length;i++){if(root.childs[i]!=null){char ch=(char) (i+'a');递归调用前序遍历String tempStr=prefixs+ch;map.putAll(preTraversal(root.childs[i], tempStr));}}}return map;}/*** 判断某字串是否在字典树中* @param word* @return true if exists ,otherwise  false*/public boolean isExist(String word){return search(this.root, word);}/*** 查询某字串是否在字典树中* @param word* @return true if exists ,otherwise  false*/private boolean search(Node root,String word){char[] chs=word.toLowerCase().toCharArray();for(int i=0,length=chs.length; i<length;i++){int index=chs[i]-'a';if(root.childs[index]==null){///如果不存在,则查找失败return false;}root=root.childs[index];}return true;}/*** 得到以某字串为前缀的字串集,包括字串本身! 类似单词输入法的联想功能* @param prefix 字串前缀* @return 字串集以及出现次数,如果不存在则返回null*/public HashMap<String, Integer> getWordsForPrefix(String prefix){return getWordsForPrefix(this.root, prefix);}/*** 得到以某字串为前缀的字串集,包括字串本身!* @param root* @param prefix* @return 字串集以及出现次数*/private HashMap<String, Integer> getWordsForPrefix(Node root,String prefix){HashMap<String, Integer> map=new HashMap<>();char[] chrs=prefix.toLowerCase().toCharArray();for(int i=0, length=chrs.length; i<length; i++){int index=chrs[i]-'a';if(root.childs[index]==null){return null;}root=root.childs[index];}///结果包括该前缀本身///此处利用之前的前序搜索方法进行搜索return preTraversal(root, prefix);}public static void main(String args[]){Trie_Tree trie = new Trie_Tree();trie.insert("I");trie.insert("Love");trie.insert("China");trie.insert("China");trie.insert("China");trie.insert("China");trie.insert("China");trie.insert("xiaoliang");trie.insert("xiaoliang");trie.insert("man");trie.insert("handsome");trie.insert("love");trie.insert("chinaha");trie.insert("her");trie.insert("know");HashMap<String,Integer> map=trie.getAllWords();for(String key:map.keySet()){System.out.println(key+" 出现: "+ map.get(key)+"次");}map=trie.getWordsForPrefix("chin");System.out.println("\n\n包含chin(包括本身)前缀的单词及出现次数:");for(String key:map.keySet()){System.out.println(key+" 出现: "+ map.get(key)+"次");}if(trie.isExist("xiaoming")==false){System.out.println("\n\n字典树中不存在:xiaoming ");}}
}

love 出现: 2次
handsome 出现: 1次
china 出现: 5次
her 出现: 1次
xiaoliang 出现: 2次
i 出现: 1次
know 出现: 1次
man 出现: 1次
chinaha 出现: 1次包含chin(包括本身)前缀的单词及出现次数:
china 出现: 5次
chinaha 出现: 1次字典树中不存在:xiaoming Process finished with exit code 0

参考文献

https://blog.csdn.net/abcd_d_/article/details/40116485?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-12.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-12.nonecase

字典树(java实现)相关推荐

  1. Tri树(字典树JAVA版)联想输入法所用的数据结构

    又到了快复试的时候了.遥想去年此时,心情忐忑不安,复试机试差点挂掉.当时考的是,联想输入法,想想都恐怖.这段时间写算法,顺便把那个给写了.也算最后纪念一下我的考研.我爱新学校,我也爱我的同学和老师,我 ...

  2. 字典树(前缀树)-Java实现

    字典树 字典树是一种树形结构,优点是利用字符串的公共前缀来节约存储空间.在这提供一个自己写的Java实现,非常简洁. 根节点没有字符路径.除根节点外,每一个节点都被一个字符路径找到. 从根节点到某一节 ...

  3. 字典树(Trie)的java实现

    一.定义 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:利用 ...

  4. [Leedcode][JAVA][第820题][字典树][Set]

    [问题描述] 给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A.例如,如果这个列表是 ["time", "me", "be ...

  5. Java实现字典树 Trie

    Java实现字典树 Trie 一.字典树介绍 二.Trie实现以及基本的插入查询操作 数组实现: HashMap实现: Trie插入(这里都以数组实现为例): Trie查询: 三.相关例题: 1.le ...

  6. Java过滤敏感词汇算法(字典树)

    定义节点 import java.util.ArrayList; import java.util.List;public class Node {private char root;private ...

  7. Java实现字典树处理海量数据查重

    问题背景: 给定两个含海量字符串的文件file1和file2,要求找出file2中哪些字符串存在于file1.处理方法很多,这里主要实现一下字典树的方法 字典树数据结构: 废话少说,直接看图(网上盗的 ...

  8. 最优雅的数据结构之一——字典树Trie(Java)

    什么是Trie? 又称单词查找树: 又叫前缀树(prefix tree): Trie树,是一种树形结构,是一种哈希树的变种. 作用: 用以较快速地进行单词或前缀查询: 用于快速检索.统计,排序和保存大 ...

  9. [Leetcode][第336题][JAVA][回文对][暴力][HashSet][字典树]

    [问题描述][困难] [解答思路] 1. 暴力(超时) 时间复杂度:O(n 2 ×m),其中 n 是字符串的数量,m 是字符串的平均长度 空间复杂度:O(1) class Solution {publ ...

最新文章

  1. wine 安装.netframework 2.0方法
  2. C++/CLI思辨录之代理构造函数
  3. Linux 内核网络协议栈运行原理
  4. 原生JS上传图片接收服务器端图片并且显示图片(主要描述blob类型)
  5. html 新append后的元素如何注册click
  6. 1042 字符统计(PAT乙级、C++)(超详细)
  7. [Leetcode][第647题][JAVA][回文子串][动态规划][中心扩展][Manacher 算法]
  8. 华为P40 Pro相机高清细节图曝光:潜望式长焦镜头抢眼
  9. ssas ssrs_如何使用SSAS表格模型数据库创建简单的SSRS报告
  10. 设计模式之(Facade)外观模式
  11. 59. 预定义超全局变量
  12. es7.3.2中文+拼音分词 排除同音字
  13. sql插入数据的方式
  14. 10个最新交互式Web设计实例欣赏
  15. 东芝停电事件可能导致Q3闪存市场价格波动
  16. 北京交通大学《机器学习》课程总结
  17. 开源中国携 200 万开发者开始真正的软件众包
  18. AI:人工智能领域之AI发展史(人工智能发展历史)之详细攻略
  19. 找到一个电信代理服务器~
  20. 我的世界服务器怎么无限刷红石,我的世界无限红石怎么做 无限红石BUG攻略

热门文章

  1. 常用CDK生成Java算法(大数异或)
  2. 华为ensp保存网络设备配置和导出导入网络设备
  3. 华为软件平台为啥不咋地?《[公司文件] 聚焦战略平台,加强血液流动,夺取未来胜利——任总、郭平、徐直军在电信软件业务汇报会上的讲话 》[转]
  4. 正数/负数的原码、反码、补码
  5. 视网膜眼底图像预测心脏病风险:Nature综述深度学习在生物医疗中的新应用
  6. python规范pep8_Python—PEP8规范
  7. Active Perl的PPM的repository添加
  8. CentOS7调整home盘空间到根目录
  9. 内部表与外部表——头歌
  10. 跟着团子学SAP PS: PS模块相关底表 PROJ/PRPS/RPSCO