1、基本概念
字典树,又称为单词查找树,Tire数,是一种树形结构,它是一种哈希树的变种。
时间复杂度分析:
假设建立了有N个单词的每个单词的最大长度是L的字典Trie树,那么插入一个单词的最坏时间复杂度是O(L),所以建树的总的时间复杂度是O(NL)
查询一个单词前缀的单词个数最坏时间复杂度是O(L).
2、基本性质
根节点不包含字符,除根节点外的每一个子节点都包含一个字符
从根节点到某一节点。路径上经过的字符连接起来,就是该节点对应的字符串
每个节点的所有子节点包含的字符都不相同
3、应用场景
典型应用是用于统计,排序和保存大量的字符串(不仅限于字符串),经常被搜索引擎系统用于文本词频统计。
4、优点
利用字符串的公共前缀来减少查询时间,最大限度的减少无谓的字符串比较,查询效率比哈希树高。
二、构建过程
1、节点定义
class TrieNode // 字典树节点 { private int num;// 有多少单词通过这个节点,即由根至该节点组成的字符串模式出现的次数 private TrieNode[] son;// 所有的儿子节点 private boolean isEnd;// 是不是最后一个节点 private char val;// 节点的值 TrieNode() { num = 1; son = new TrieNode[SIZE]; isEnd = false; } }
2、构造函数
Trie() // 初始化字典树 { root = new TrieNode(); }
3、建立字典树
// 建立字典树 public void insert(String str) // 在字典树中插入一个单词 { if (str == null || str.length() == 0) { return; } TrieNode node = root; char[] letters = str.toCharArray();//将目标单词转换为字符数组 for (int i = 0, len = str.length(); i < len; i++) { int pos = letters[i] - 'a'; if (node.son[pos] == null) //如果当前节点的儿子节点中没有该字符,则构建一个TrieNode并复值该字符 { node.son[pos] = new TrieNode(); node.son[pos].val = letters[i]; } else //如果已经存在,则将由根至该儿子节点组成的字符串模式出现的次数+1 { node.son[pos].num++; } node = node.son[pos]; } node.isEnd = true; }
4、查找是否完全匹配一个指定的字符串
// 在字典树中查找一个完全匹配的单词. public boolean has(String str) { if(str==null||str.length()==0) { return false; } TrieNode node=root; char[]letters=str.toCharArray(); for(int i=0,len=str.length(); i<len; i++) { int pos=letters[i]-'a'; if(node.son[pos]!=null) { node=node.son[pos]; } else { return false; } } //走到这一步,表明可能完全匹配,也可能部分匹配,如果最后一个字符节点为末端节点,则是完全匹配,否则是部分匹配 return node.isEnd; }
5、前序遍历字典树
// 前序遍历字典树. public void preTraverse(TrieNode node) { if(node!=null) { System.out.print(node.val+"-"); for(TrieNode child:node.son) { preTraverse(child); } } }
6、计算单词前缀的数量
// 计算单词前缀的数量 public int countPrefix(String prefix) { if(prefix==null||prefix.length()==0) { return-1; } TrieNode node=root; char[]letters=prefix.toCharArray(); for(int i=0,len=prefix.length(); i<len; i++) { int pos=letters[i]-'a'; if(node.son[pos]==null) { return 0; } else { node=node.son[pos]; } } return node.num; }
结果:
三、应用
(问题1)请你选择合适的数据结构,将所有的英文单词生成一个字典Dictionary?
(问题2)给定一个单词,判断这个单词是否在字典Dictionary中,如果在单词库中,输出这个单词出现总共出现的次数,否则输出NO?
package com.xj.test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; public class Trie { private int SIZE = 26; private TrieNode root;// 字典树的根 class TrieNode // 字典树节点 { private int num;// 有多少单词通过这个节点,即由根至该节点组成的字符串模式出现的次数 private TrieNode[] son;// 所有的儿子节点 private boolean isEnd;// 是不是最后一个节点 private char val;// 节点的值 TrieNode() { num = 1; son = new TrieNode[SIZE]; isEnd = false; } } Trie() // 初始化字典树 { root = new TrieNode(); } // 建立字典树 public void insert(String str) // 在字典树中插入一个单词 { if (str == null || str.length() == 0) { return; } TrieNode node = root; char[] letters = str.toCharArray();//将目标单词转换为字符数组 for (int i = 0, len = str.length(); i < len; i++) { int pos = letters[i] - 'a'; if (node.son[pos] == null) //如果当前节点的儿子节点中没有该字符,则构建一个TrieNode并复值该字符 { node.son[pos] = new TrieNode(); node.son[pos].val = letters[i]; } else //如果已经存在,则将由根至该儿子节点组成的字符串模式出现的次数+1 { node.son[pos].num++; } node = node.son[pos]; } node.isEnd = true; } // 计算单词前缀的数量 public int countPrefix(String prefix) { if(prefix==null||prefix.length()==0) { return-1; } TrieNode node=root; char[]letters=prefix.toCharArray(); for(int i=0,len=prefix.length(); i<len; i++) { int pos=letters[i]-'a'; if(node.son[pos]==null) { return 0; } else { node=node.son[pos]; } } return node.num; } // 打印指定前缀的单词 public String hasPrefix(String prefix) { if (prefix == null || prefix.length() == 0) { return null; } TrieNode node = root; char[] letters = prefix.toCharArray(); for (int i = 0, len = prefix.length(); i < len; i++) { int pos = letters[i] - 'a'; if (node.son[pos] == null) { return null; } else { node = node.son[pos]; } } preTraverse(node, prefix); return null; } // 遍历经过此节点的单词. public void preTraverse(TrieNode node, String prefix) { if (!node.isEnd) { for (TrieNode child : node.son) { if (child != null) { preTraverse(child, prefix + child.val); } } return; } System.out.println(prefix); } // 在字典树中查找一个完全匹配的单词. public boolean has(String str) { if(str==null||str.length()==0) { return false; } TrieNode node=root; char[]letters=str.toCharArray(); for(int i=0,len=str.length(); i<len; i++) { int pos=letters[i]-'a'; if(node.son[pos]!=null) { node=node.son[pos]; } else { return false; } } //走到这一步,表明可能完全匹配,可能部分匹配,如果最后一个字符节点为末端节点,则是完全匹配,否则是部分匹配 return node.isEnd; } // 前序遍历字典树. public void preTraverse(TrieNode node) { if(node!=null) { System.out.print(node.val+"-"); for(TrieNode child:node.son) { preTraverse(child); } } } public TrieNode getRoot() { return this.root; } public static void main(String[]args) throws IOException { Trie tree=new Trie(); String[] dictionaryData= {"hello","student","computer","sorry","acm","people","experienced","who","reminds","everyday","almost"}; //构建字典 for(String str:dictionaryData) { tree.insert(str); } String filePath="C:\\Users\\Administrator\\Desktop\\sourceFile.txt"; File file=new File(filePath); if(file.isFile() && file.exists()) { InputStreamReader read = new InputStreamReader(new FileInputStream(file)); BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; Map<String,Integer> countMap=new HashMap<String,Integer>(); while((lineTxt = bufferedReader.readLine())!= null) { if(tree.has(lineTxt)) { if(countMap.containsKey(lineTxt)) { countMap.put(lineTxt, countMap.get(lineTxt)+1); } else { countMap.put(lineTxt, 1); } } else { System.out.println(lineTxt+"不在字典中!"); } } for(String s:countMap.keySet()) { System.out.println(s+"出现的次数"+countMap.get(s)); } read.close(); } } }
text文件内容:
结果:
相关推荐
基于Java链表实现的字典树(trie),实现了增删改查等功能,它说摘要必须大于50字我还能说啥啥啥啥
资源链接:https://github.com/AbelZhou/PHP-TrieTree
Java实现字典树TrieTree,可用于计算出四六级试题的高频词.
包含了对字典树的多种操作。详情请见本人博客:http://blog.csdn.net/lemon_tree12138/article/details/49177509
ACM Trie树 模板,字典树模板,数据结构
hash trie树 字典树,完整的sdk开发包 具有说明文档
字典树,java语言 字典树,trie 每个节点26个子节点
主要介绍了PHP字典树(Trie树)定义与实现方法,简单描述了字典树的概念并结合实例形式分析了字典树的定义与使用方法,需要的朋友可以参考下
字典树:又称为Trie,是一种用于快速检索的多叉树结构。
从Trie树(字典树)谈到后缀树 -- 程序员面试必备
字典树,Trie树,查找插入效率都很高的一种高级数据结构。
C 字典树实现目的提供字典的实现,其中包含单词及其相关描述,并允许用户用大量信息填充它,并且仍然可以在可接受和有效的时间范围内进行搜索。显现dictionary.h 字典实现的头文件,它创建了字典 API 应该如何工作的...
NULL 博文链接:https://auauau.iteye.com/blog/675645
一棵用List来存储子结点的字典树——当然,也可以用哈希表等形式存储。 这篇笔记记录了构建思路,文末是源码 一、构建思路 Step1 设计结点——数据结构 Step2 实现相应的操作方法——增删改查 Step1 设计结点 我们...
Trie多被用来查找和统计字符串,利用公共前缀来减少搜索时间,下面我们就来详解字典树Trie结构及其Python代码实现
字典树:又称为Trie,是一种用于快速检索的多叉树结构。Trie把要查找的关键词看作一个字符序列,并根据构成关键词字符的先后顺序构造用于检索的树结构;一棵m度的Trie树或者为空,或者由m棵m度的Trie树构成。
Trie树,又称字典树或前缀树,关于它的结构就不详细介绍了。Trie树在单词统计、前缀匹配等很多方面有很大用处。下面这篇文章主要介绍了Trie树,以及Java实现如何Trie树,有需要的朋友可以参考借鉴,下面来一起看看吧...
有时,我们会碰到对字符串的排序,若采用一些经典的排序算法,则时间复杂度一般为O(n*lgn),但若采用Trie树,则时间复杂度仅为O(n)
傻傻分不清楚Trie树,又称字典树,是一种树形数据结构被广泛用于字符串的统计Trie树的构造Trie树节点的每个儿子都代表一个字母那么就可以用某节点到根的路径来