`
543089122
  • 浏览: 153188 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

简单_Trie树与三叉Trie树

阅读更多
package sunfa.tree;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 参考:http://book.51cto.com/art/201106/269044.htm
 * Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种
 * 。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计
 * 。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
 * 
 * 网上有许多人错误的把Trie树理解为二叉的,其实Trie树可以是二叉,也可以是多叉的,
 * 本例建立的就是多叉的Trie树,每个节点的子节点集合是一个HashMap,可以这样理解:
 * 根节点下面有N个子节点,第K个子节点下面也是N个子节点。
 * 
 * Trie树的查询次数和key是有关系的,key的长度决定了树的深度。
 * Trie是典型的以空间还时间的快速查找树,适合于对速度要求非常高的场景。
 * 像lucene啊,搜索引擎啊,黑名单啊等就大量使用到Trie树。
 * 最后不的不说Trie对空间的浪费是及其大的。
 * 
 */
public class TrieTreeDemo1 {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		TrieTreeDemo1 tree = new TrieTreeDemo1();
		for (int i = 0; i < 20; i++) {
			map.put("key,value" + i, "value" + i);
			tree.addWord("key,value" + i, "value" + i);
		}
		System.out.println("search:");
		Iterator<String> it = map.keySet().iterator();
		while (it.hasNext()) {
			String key = it.next().toString();
			System.out.println(tree.search(key));
		}
		System.out.println(tree.search("ke1"));
	}

	private Entry root = new Entry();

	public void addWord(String key, String o) {
		Entry node = root;
		for (int i = 0; i < key.length(); i++) {
			char c = key.charAt(i);
			if (node.children.get(c) == null) {
				node.children.put(c, new Entry(c));
			}
			node = node.children.get(c);
		}
		node.o = o;
	}

	public Object search(String key) {
		Entry node = root;
		int count = 0;
		for (int i = 0; i < key.length(); i++) {
			count++;
			if (node.children.get(key.charAt(i)) == null)
				return null;
			if (node.children.get(key.charAt(i)).o != null) {
				System.out.println("key:" + key + ",count:" + count);
				return node.children.get(key.charAt(i)).o;
			}
			node = node.children.get(key.charAt(i));
		}
		return null;
	}

	static class Entry {
		Map<Character, Entry> children = new HashMap<Character, TrieTreeDemo1.Entry>();
		char c;
		String o;

		public Entry(char c) {
			this.c = c;
		}

		public Entry() {
		}
	}
}

package sunfa.tree;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 三叉Trie树 http://book.51cto.com/art/201106/269045.htm
 * Trie树应用http://eriol.iteye.com/blog/1166118 三叉Trie树在占用空间上要比N叉树好的多。
 * 在一个三叉搜索树(Ternary Search
 * Trie)中,每一个节点包括一个字符,但和数字搜索树不同,三叉搜索树只有三个指针:一个指向左边的树;一个指向右边的树
 * ;还有一个向下,指向单词的下一个数据单元
 * 。三叉搜索树是二叉搜索树和数字搜索树的混合体。它有和数字搜索树差不多的速度但是和二叉搜索树一样只需要相对较少的内存空间。
 * 树是否平衡取决于单词的读入顺序。如果按排序后的顺序插入
 * ,则生成方式最不平衡。单词的读入顺序对于创建平衡的三叉搜索树很重要,但对于二叉搜索树就不太重要。通过选择一个排序后数据单元集合的中间值
 * ,并把它作为开始节点,我们可以创建一个平衡的三叉树。可以写一个专门的过程来生成平衡的三叉树词典。
 * 
 * Patricia Tree 简称PAT tree。 它是 trie 结构的一种特殊形式。是目前信息检索领域应用十分成功的索引方
 * http://hxraid.iteye.com/blog/topic?show_full=true
 */
public class TernarySearchTrie {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		int size = 20;
		TernarySearchTrie tree = new TernarySearchTrie();
		for (int i = 0; i < size; i++) {
			map.put("tkey" + i, "value" + i);
			tree.addWord("tkey" + i);
		}
		System.out.println("search:");
		Iterator<String> it = map.keySet().iterator();
		while (it.hasNext()) {
			String key = it.next().toString();
			Entry node = tree.search(key);
			System.out.println(node.data.get("value") + ",查找次数:"
					+ node.data.get("count"));
		}
	}

	private Entry root = new Entry();

	public Entry addWord(String key) {
		if (key == null || key.trim().length() == 0)
			return null;
		// 调试的时候发现个问题很是不明白,为什么根节点一开始就有不为NULL的right节点,并且这个right节点的splitchar是k
		// 终于发现了,java程序在调试的时候可能存在一个预编译的问题,某些链表式的对象调试的时候DEBUG信息不是很准备,甚至错误,比如链表啊,i++等操作调试就会看到错误的信息,这样的情况用打印语句调试算了。
		Entry node = root;
		int i = 0;
		while (true) {
			int diff = key.charAt(i) - node.splitchar;
			char c = key.charAt(i);
			if (diff == 0) {// 当前单词和上一次的相比较,如果相同
				i++;
				if (i == key.length()) {
					node.data = new HashMap<Object, Object>();
					node.data.put("value", key);
					return node;
				}
				if (node.equals == null)
					node.equals = new Entry(key.charAt(i));// 这里要注意,要获取新的单词填充进去,因为i++了
				node = node.equals;
			} else if (diff < 0) {// 没有找到对应的字符,并且下一个左或右节点为NULL,则会一直创建新的节点
				if (node.left == null)
					node.left = new Entry(c);
				node = node.left;
			} else {
				if (node.right == null)
					node.right = new Entry(c);
				node = node.right;
			}
		}
	}

	public Entry search(String key) {
		if (key == null || key.trim().length() == 0)
			return null;
		Entry node = root;
		int count = 0, i = 0;
		while (true) {
			if (node == null)
				return null;
			int diff = key.charAt(i) - node.splitchar;
			count++;
			if (diff == 0) {
				i++;
				if (i == key.length()) {
					node.data.put("count", count);
					return node;
				}
				node = node.equals;
			} else if (diff < 0) {
				node = node.left;
			} else {
				node = node.right;
			}
		}
	}

	/**
	 * 三叉Trie树存在3个节点,左右子节点和二叉树类似,以前key都是存放在二叉树的当前节点中,在三叉树中单词是存放在中间子树的。
	 */
	static class Entry {
		Entry left;
		Entry right;
		Entry equals;// 比对成功就放到中间节点
		char splitchar;// 单词
		Map<Object, Object> data;// 扩展数据域,存放 检索次数,关键码频率等信息。

		public Entry(char splitchar) {
			this.splitchar = splitchar;
		}

		public Entry() {
		}
	}
}
分享到:
评论

相关推荐

    C#编写的三叉Trie树

    对于一般的Trie树的数据结构,它的实现简单但是空间效率极低。三叉搜索树使用了一种聪明的手段去解决字典树的内存问题(空的指针数组)。为了避免多余的指针占用内存,每个节点不再用数组来表示,而是表示成“树中有...

    基于三叉树的中文字典结构

    三叉树,又称为Trie或Prefix Tree,是一种有序树数据结构,它能有效存储和查找具有公共前缀的字符串。与二叉搜索树不同,三叉树每个节点通常有三个子节点,分别代表字符集中的三个不同字符。这样的设计使得三叉树在...

    AC-TernarySearchTrie

    它基于有限状态自动机(FSA)的概念,通过构建一种特殊的自动机——三叉搜索树(Ternary Search Trie,TST),来实现对大量模式串的并行查找。在AC自动机中,每个节点不仅包含当前字符的信息,还存储了前缀指向的...

    搜索引擎核心技术与实现

    - **查找词典算法**:包括标准Trie树和三叉Trie树的算法。 - **中文分词的原理与流程**:解释了全切分词图的保存和形成,以及基于概率语言模型和N元分词方法的分词技术。 - **语料库与新词发现**:讨论了如何建立...

    Fast Algorithms for sorting and Search strings

    这些算法结合了快速排序(Quicksort)与基数排序(Radix Sort)、Trie 树与二叉搜索树(Binary Search Tree),不仅在理论上具有优越性,在实际应用中也表现出色。 #### 一、理论背景 ##### 1.1 快速排序 快速...

    生锈的三元搜索树集合,并尽可能使用与std :: collections类似的API。-Rust开发

    三元搜索树是trie的一种类型(有时称为前缀树),其中将节点排列在其中一种类似于二叉搜索树的方式,但是最多具有三个子级,而不是二叉树的限制,与其他前缀树一样,三叉搜索树可以用作关联映射结构,并具有增量字符...

    同学录管理系统.rar

    系统还可能包含搜索功能,这可能涉及到模糊匹配和排序算法,如Trie树(字典树)用于快速查找类似姓名,或者快速排序和归并排序用于对学友信息进行排序。 最后,为了便于用户界面的交互,可能还会涉及到数据库技术,...

    Java数据结构与算法源代码

    a.10 个数据结构:数组,链表,栈,队列,散列表,三叉树,堆,跳表图,Trie 树。 b.10 个算法:递归,排序,二分查找,搜索,哈希算法,贪心算法,分治算法,回溯算法,动态规划,字符串匹配算法。 四。学习技巧 ...

    数据结构(王)c元代码

    范例1-100 按关键字符串遍历Trie树 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 范例1-102...

    数据结构算法实现(严蔚敏版配套实现程序)

    范例1-100 按关键字符串遍历Trie树 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 范例1-102...

    数据结构算法实现(严蔚敏版配套实现程序)

    范例1-100 按关键字符串遍历Trie树 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 范例1-102...

    数据结构 严蔚敏 代码

    范例1-100 按关键字符串遍历Trie树 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 范例1-102...

    解密搜索引擎技术实战:Lucene&Java精华版

    - **4.2.2 三叉Trie树**:介绍了三叉Trie树的特点及其优势。 - **4.3 中文分词的原理**:详细介绍了中文分词的基本原理和技术背景。 - **4.4 中文分词流程与结构**:讲解了中文分词的一般流程及结构设计。 - **4.5 ...

    C 开发金典

    范例1-100 按关键字符串遍历Trie树 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 ...

    C语言通用范例开发金典.part2.rar

    范例1-100 按关键字符串遍历Trie树 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 ...

    C语言通用范例开发金典.part1.rar

    范例1-100 按关键字符串遍历Trie树 301 ∷相关函数:SearchTrie函数 1.6.8 哈希表的基本操作 306 范例1-101 哈希表的基本操作 306 ∷相关函数:SearchHash函数 1.7 图 311 1.7.1 图的邻接矩阵存储表示 311 ...

    Nginx服务器中location配置的一些基本要点解析

    对于字符串匹配,Nginx采用了一种高效的三叉字符串排序树(Trie树)结构,以快速找到最匹配的`location`。这种数据结构在构建时就考虑到了平衡性,从而确保了高效查找。 字符串匹配的`location`类型有以下几种: 1...

    nginx 配置location匹配规则实例讲解

    Nginx为了提高匹配效率,对字符串匹配的`location`采用了三叉字符串排序树(Trie树)的数据结构。这种方式使得搜索效率更高,尤其是在大量`location`配置的情况下。 为了更好地理解和应用这些规则,以下是一些实用...

Global site tag (gtag.js) - Google Analytics