来源于英文“retrieval”.   Trie树就是字符树,其核心思想就是空间换时间。

举个简单的例子。
   给你100000个长度不超过10的单词。对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。
这题当然可以用hash来,但是我要介绍的是trie树。在某些方面它的用途更大。比如说对于某一个单词,我要询问它的前缀是否出现过。这样hash就不好搞了,而用trie还是很简单。

现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否有它。那么这个算法的复杂度就是O(n^2)。显然对于100000的范围难以接受。现在我们换个思路想。假设我要查询的单词是abcd,那么在他前面的单词中,以b,c,d,f之类开头的我显然不必考虑。而只要找以a开头的中是否存在abcd就可以了。同样的,在以a开头中的单词中,我们只要考虑以b作为第二个字母的……这样一个树的模型就渐渐清晰了……

假设有b,abc,abd,bcd,abcd,efg,hii这6个单词,我们构建的树就是这样的。

对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。 
   那么,对于一个单词,我只要顺着他从根走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。把这个节点标记为红色,就相当于插入了这个单词。

我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。(转自一大牛)

Trie树的java代码 实现如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; /** *//**
* A word trie which can only deal with 26 alphabeta letters.
* @author Leeclipse
* @since 2007-11-21
*/ public class Trie{ private Vertex root;//一个Trie树有一个根节点 //内部类
protected class Vertex{//节点类
protected int words;
protected int prefixes;
protected Vertex[] edges;//每个节点包含26个子节点(类型为自身)
Vertex() {
words = ;
prefixes = ;
edges = new Vertex[];
for (int i = ; i < edges.length; i++) {
edges[i] = null;
}
}
} public Trie () {
root = new Vertex();
} /** *//**
* List all words in the Trie.
*
* @return
*/ public List< String> listAllWords() { List< String> words = new ArrayList< String>();
Vertex[] edges = root.edges; for (int i = ; i < edges.length; i++) {
if (edges[i] != null) {
String word = "" + (char)('a' + i);
depthFirstSearchWords(words, edges[i], word);
}
}
return words;
} /** *//**
* Depth First Search words in the Trie and add them to the List.
*
* @param words
* @param vertex
* @param wordSegment
*/ private void depthFirstSearchWords(List words, Vertex vertex, String wordSegment) {
Vertex[] edges = vertex.edges;
boolean hasChildren = false;
for (int i = ; i < edges.length; i++) {
if (edges[i] != null) {
hasChildren = true;
String newWord = wordSegment + (char)('a' + i);
depthFirstSearchWords(words, edges[i], newWord);
}
}
if (!hasChildren) {
words.add(wordSegment);
}
} public int countPrefixes(String prefix) {
return countPrefixes(root, prefix);
} private int countPrefixes(Vertex vertex, String prefixSegment) {
if (prefixSegment.length() == ) { //reach the last character of the word
return vertex.prefixes;
} char c = prefixSegment.charAt();
int index = c - 'a';
if (vertex.edges[index] == null) { // the word does NOT exist
return ;
} else { return countPrefixes(vertex.edges[index], prefixSegment.substring()); } } public int countWords(String word) {
return countWords(root, word);
} private int countWords(Vertex vertex, String wordSegment) {
if (wordSegment.length() == ) { //reach the last character of the word
return vertex.words;
} char c = wordSegment.charAt();
int index = c - 'a';
if (vertex.edges[index] == null) { // the word does NOT exist
return ;
} else {
return countWords(vertex.edges[index], wordSegment.substring()); } } /** *//**
* Add a word to the Trie.
*
* @param word The word to be added.
*/ public void addWord(String word) {
addWord(root, word);
} /** *//**
* Add the word from the specified vertex.
* @param vertex The specified vertex.
* @param word The word to be added.
*/ private void addWord(Vertex vertex, String word) {
if (word.length() == ) { //if all characters of the word has been added
vertex.words ++;
} else {
vertex.prefixes ++;
char c = word.charAt();
c = Character.toLowerCase(c);
int index = c - 'a';
if (vertex.edges[index] == null) { //if the edge does NOT exist
vertex.edges[index] = new Vertex();
} addWord(vertex.edges[index], word.substring()); //go the the next character
}
} public static void main(String args[]) //Just used for test
{
Trie trie = new Trie();
trie.addWord("China");
trie.addWord("China");
trie.addWord("China"); trie.addWord("crawl");
trie.addWord("crime");
trie.addWord("ban");
trie.addWord("China"); trie.addWord("english");
trie.addWord("establish");
trie.addWord("eat");
System.out.println(trie.root.prefixes);
System.out.println(trie.root.words); List< String> list = trie.listAllWords();
Iterator listiterator = list.listIterator(); while(listiterator.hasNext())
{
String s = (String)listiterator.next();
System.out.println(s);
} int count = trie.countPrefixes("ch");
int count1=trie.countWords("china");
System.out.println("the count of c prefixes:"+count);
System.out.println("the count of china countWords:"+count1); }
}
运行:
C:\test>java Trie ban
china
crawl
crime
eat
english
establish
the count of c prefixes:
the count of china countWords:

Trie 树 及Java实现的更多相关文章

  1. 双数组Trie树(DoubleArrayTrie)Java实现

    http://www.hankcs.com/program/java/%E5%8F%8C%E6%95%B0%E7%BB%84trie%E6%A0%91doublearraytriejava%E5%AE ...

  2. Trie树的java实现

    leetcode 地址: https://leetcode.com/problems/implement-trie-prefix-tree/description/ 难度:中等 描述:略 解题思路: ...

  3. leetcode网站中找到的关于trie树的JAVA版本介绍

    class TrieNode { // R links to node children private TrieNode[] links; private final int R = 26; pri ...

  4. Trie树的应用:查询IP地址的ISP

    1. 问题描述 给定一个IP地址,如何查询其所属的ISP,如:中国移动(ChinaMobile),中国电信(ChinaTelecom),中国铁通(ChinaTietong)?现有ISP的IP地址区段可 ...

  5. 从Trie树到双数组Trie树

    Trie树 原理 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,能在常数时间O(len)内实现插入和查 ...

  6. Trie树(转:http://blog.csdn.net/arhaiyun/article/details/11913501)

    Trie 树, 又称字典树,单词查找树.它来源于retrieval(检索)中取中间四个字符构成(读音同try).用于存储大量的字符串以便支持快速模式匹配.主要应用在信息检索领域. Trie 有三种结构 ...

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

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

  8. java实现的Trie树数据结构

    近期在学习的时候,常常看到使用Trie树数据结构来解决这个问题.比方" 有一个1G大小的一个文件.里面每一行是一个词.词的大小不超过16字节,内存大小限制是1M. 返回频数最高的100个词. ...

  9. Trie树(字典树)的介绍及Java实现

    简介 Trie树,又称为前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串.与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定.一个节点的所有子孙都有相同的前缀,也 ...

随机推荐

  1. MVC同一页面循环显示数据库记录(答题/投票系统)

    ) { //int id = 1; list newlist = db.lists.Find(id); //var q = from p in db.lists where p.id==1 selec ...

  2. CentOS6.5修改mysql数据文件路径

    1.停止mysql服务      service mysql stop 2.移动数据文件位置(保留原文件权限)      cp -a /var/lib/mysql /mysqldata 3.修改/et ...

  3. Windows Azure 配置多个站点的虚拟网络连接

    通过上一篇"Windows Azure 虚拟网络配置(Site to Site)" 我们建立了可以进行Site to Site连接的虚拟网络,配置过后有些朋友会有疑问:如果需要连接 ...

  4. the behavior of the UICollectionViewFlowLayout is not defined because:

    the behavior of the UICollectionViewFlowLayout is not defined because:    the item height must be le ...

  5. ubuntu cloud-archive 软件包 无法验证包来源

  6. sysctl.conf

    linux系统接口 允许改变正在运作linux系统接口Tcp/IP堆栈和虚拟内存系统的高级选项 用来控制Linux网络配置/proc/sys/net/core/ TCP/IP参数修改添加到/etc/s ...

  7. 第二百零七天 how can I坚持

    都这么一大把年纪了,还没正事,哎.. mysql ifnull(expr,expr),oracle nvl();去null函数. 每天也没什么事. 哎,每天 也总有那么点事. 刘松.李承杰,都是些什么 ...

  8. javascript日期格式化方法汇总

    本文给大家汇总介绍了javascript格式化日期时间的几种常用方法,个人对最后一种个性化输出时间比较有兴趣,基本上只要项目中能用到都是使用这种,推荐给小伙伴们. 方法一: ? 1 2 3 4 5 6 ...

  9. SqlAgent备份脚本

    ) ) set @dbname='emcp' set @back_path= 'e:\'+@dbname+'\'+@dbname ),) )) )) )) +'.bak' exec('use ['+@ ...

  10. 微信get post请求到微信服务器 模版 素材操作

    1:素材管理 官方文档 package org.konghao.weixin.media; import java.io.File; import java.io.IOException; impor ...