`
leichenlei
  • 浏览: 128726 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Trie字典树、数字查找、键树

阅读更多

1,需要先将要被查找的文字通过structure方法按照拼音构建成一棵树,每个匹配节点上装有查找目标对象。

 

2,完成的功能:用户在输入框里输入拼音或者汉字,输入内容转化成拼音,然后按照拼音遍历树,找到结果。

 

3,用到了开元包pinyin4j

 

4,没有考虑多音字。可以按需要对多音字做多路径存储。子节点可以优化成map结构,优化遍历速度。

 

package com.test.common.utils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Trie字典树类,节点用内部类Node表示,提供构建树、插入节点、搜索、等方法。
 * 需要优化的地方:1,多音字,2子节点的存储结构和查找
 * @author yfchenlei
 * @date 2012-9-12
 */
public class Trie<T> implements Serializable{
	private static final long serialVersionUID = 5694541776693908755L;
	/**
	 * 根节点
	 */
	private Node<T> root;
	/**
	 * 最大搜索结果个数
	 */
	private int maxResult = 10;
	/**
	 *  默认构造方法
	 */
	public Trie(){
		
	}
	/**
	 * 带参构造方法
	 * @param maxResult 最大搜索结果个数
	 */
	public Trie(int maxResult){
		this.maxResult = maxResult;
	}
	/**
	 * 根据传入数据集合构建一颗字典树
	 * @param words 数据集合
	 */
	public void structure(Map<String, T> items){
		root = new Node<T>('0');
		if(items == null){
			return;
		}
		Iterator<String> it = items.keySet().iterator();
		while(it.hasNext()){
			String key = it.next();
			T value= items.get(key);
			if(value != null){
				insert(key, value);
			}
		}
	}
	/**
	 * 向字典树插入一个数据,word。
	 * @author yfchenlei
	 * @date 2012-9-12
	 * @param word 要插入到字典树的数据
	 */
	public void insert(String word,T item){
		String pinyin = PinYin.cn2Pinyin(word);
		if(root == null){
			root = new Node<T>('0');
		}
		Node<T> curNode = root;
		int wordLength = pinyin.length();
		for(int i = 0; i< wordLength; i++){
			char value = pinyin.charAt(i);
			Node<T> nextNode = curNode.getChild(value);
			if(nextNode == null){
				nextNode = new Node<T>(value);
				curNode.addChild(nextNode);
			}
			curNode = nextNode;
		}
		curNode.addItem(item);
	}
	/**
	 * 根据输入的word的拼音,查找符合这个拼音前缀的所有集合,但不超过最大结果个数。
	 * @author yfchenlei
	 * @date 2012-9-12
	 * @param word 根据这个数据进行查找
	 * @return 符合条件的集合
	 */
	public List<T> find(String word){
		List<T> result = new ArrayList<T>(maxResult);
		if(root == null || word == null){
			return result;
		}
		String pinyin = PinYin.cn2Pinyin(word);
		Node<T> curNode = root;
		for(int i = 0; i < pinyin.length(); i++){
			Node<T> child = curNode.getChild(pinyin.charAt(i));
			if(child != null){
				curNode = child;
			}else{
				return result;
			}
		}
		result = traverse(curNode, result);
		return result;
	}
	/**
	 * 遍历字典树的递归方法,每次递归,将结果积累到result参数。
	 * @author yfchenlei
	 * @date 2012-9-12
	 * @param node 当前节点
	 * @param result 结果集合
	 * @return 返回最后的集合
	 */
	private List<T> traverse(Node<T> node, List<T> result){
		if(node == null || result.size() == maxResult){
			return result;
		}
		List<T> items = node.getItems();
		if(items != null){
			if(result.size() + items.size() > maxResult){
				for(int i = 0; i < maxResult - result.size(); i++){
					result.add(items.get(i));
				}
			}else{
				result.addAll(node.getItems());
			}
		}
		Node<T>[] children = node.getChildren();
		if(children != null){
			for(int i = 0; i < children.length; i++){
				if(result.size() == maxResult){
					break;
				}
				traverse(children[i], result);
			}
		}
		return result;
	}

	/**
	 * trie的子类,表示树节点
	 * @author yfchenlei
	 * @date 2012-9-12
	 */
	@SuppressWarnings("hiding")
	class Node<T> implements Serializable{
		private static final long serialVersionUID = -7145041421696945423L;
		/**
		 * 节点的路径值
		 */
		private char value;
		/**
		 * 子节点集合
		 */
		private Node<T>[] children;
		/**
		 * 节点中的值集合,因为拼音可能重复,所以是集合。
		 */
		private List<T> items;
	
		public Node(char value){
			this.value = value;
		}
		
		public void addItem(T item){
			if(items == null){
				items = new ArrayList<T>(1);
			}
			items.add(item);
		}
		
		public void addChild(Node<T> node){
			if(children == null){
				this.children = new Node[26];
			}
			children[node.getValue() - 'a'] = node;
		}
		
		public Node<T> getChild(char value){
			int pos = value - 'a';
			if(children == null){
				return null;
			}
			return children[pos];
		}
		
		public char getValue() {
			return value;
		}

		public Node<T>[] getChildren() {
			return children;
		}
		
		public List<T> getItems() {
			return items;
		}
	}
}

 用到的转化拼音工具:

 

package com.test.common.utils;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
/**
 * 汉字转拼音支持工具
 * @author yfchenlei
 * @date 2012-9-13
 */
public class PinYin {
	private static HanyuPinyinOutputFormat defaultFormat;
	
	static{
		defaultFormat = new HanyuPinyinOutputFormat(); 
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); 
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
	}
	
	public static String cn2Pinyin(String cn){
		StringBuffer result = new StringBuffer();
		char[] chars = cn.toCharArray();
		try {
	        for(int i = 0; i < chars.length; i++){
	        	if(chars[i] > 128){
	        		String[] pinyin = PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat);
        			result.append(pinyin[0]);
	        	}else{
	        		char letter = Character.toLowerCase(chars[i]);
	        		if(letter >= 98 && letter <= 122)
	        		result.append(chars[i]);
        		}
	        }
		} catch (BadHanyuPinyinOutputFormatCombination e) {
			e.printStackTrace();
			return null;
		}
        return result.toString();
	}
}

 

 

分享到:
评论
3 楼 leichenlei 2012-10-11  
wd_demon 写道
刚看了下 Trie树 ,终于看明白了。

然后你说 子节点 用map会提高效率,这个为什么啊?

ps:发现PinYin的这段代码有BUG啊,

if(chars[i] > 128){ 
                    String[] pinyin = PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat); 
                    result.append(pinyin[0]);    //这个会包空指针啊~
                }




嗯,是有bug。
用数组插入快啊,但是查找遍历浪费时间;用map查询比较快,hash取值相当快啊~~
这个树目的是快速查找,所以牺牲插入速度,优化查找速度是对的啊.
2 楼 wd_demon 2012-09-27  
刚看了下 Trie树 ,终于看明白了。

然后你说 子节点 用map会提高效率,这个为什么啊?

ps:发现PinYin的这段代码有BUG啊,

if(chars[i] > 128){ 
                    String[] pinyin = PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat); 
                    result.append(pinyin[0]);    //这个会包空指针啊~
                }

1 楼 wd_demon 2012-09-27  
拿这个代码跑了一下,只支持顺序搜索啊,比如 张三“zhangsan” 我打个san就搜不出来了~ 看了下Trie这个类 没看懂~

相关推荐

    字典树(Trie)的基本使用

    - **电话号码查找**:在电话簿中,通过字典树可以迅速找到所有以特定数字序列开头的电话号码。 了解并掌握字典树的概念及其应用,对于提升编程能力和解决实际问题具有重要意义。通过阅读和分析"DemoNumberTrie"中的...

    trie树所有代码,试题打包

    Trie树,又称前缀树或字典树,是一种用于存储字符串的数据结构,它在IT领域尤其是数据结构和算法的学习中占据着重要的地位。这个压缩包包含的“王赟.doc”和“王赟.ppt”很可能是关于Trie树的详细讲解和实践题目,...

    深度优先遍历字典树(统计单词出现的个数)

    在字典树(Trie,也称为前缀树或数字检索树)中应用深度优先遍历,可以有效地统计单词出现的个数。字典树是一种数据结构,常用于存储大量字符串,它允许我们快速查找以特定前缀开头的所有单词。 在Java中,实现字典...

    Python实现简单字典树的方法

    字典树的主要特点是它能通过键的公共前缀来组织数据,使得查找具有相同前缀的字符串变得非常高效。在本篇内容中,我们将深入探讨Python实现简单字典树的方法。 首先,我们需要了解字典树的基本结构。字典树是由节点...

    xor.zip_puttinge9a_区间异或最大_字典树查找区间异或最大值_寻找最窄区间_异或最大值

    在给定的压缩包文件中,我们可以看到一个名为"xor.zip_puttinge9a_区间异或最大_字典树查找区间异或最大值_寻找最窄区间_异或最大值"的文件,这暗示了使用字典树(Trie)数据结构来解决这一问题。 首先,让我们深入...

    Python Trie树实现字典排序

    什么是Trie树 Trie树通常又称为字典树、单词查找树或前缀树,是一种用于快速检索的多叉树结构。如图数字的字典是一个10叉树: 同理小写英文字母或大写英文字母的字典数是一个26叉树。如上图可知,Trie树的根结点是...

    DS.rar_ trie_TRIE_site:www.pudn.com_二叉树 注释_图 数据结构

    接下来是Trie树,也被称为前缀树或字典树。Trie树是一种用于存储字符串的数据结构,通过使用节点间的分支来表示字符串的字符。"Trie.cpp"很可能是实现Trie树插入、查找和删除操作的代码。Trie树在字符串查找、自动...

    javascript trie前缀树的示例

    它的名字来源于英文单词"retrieval",被称作前缀字、单词查找树或字典树。Trie树是一种特殊的哈希树变种,通过利用字符串的公共前缀来减少不必要的字符串比较,从而提高查询效率。 Trie树的基本特性如下: 1. 根...

    python 数据结构 算法 LeetCode 牛客 面试 编程之美 动态规划 字典树等等

    5. **字典树(Trie)**:字典树是一种高效的数据结构,主要用于字符串搜索。它通过将字符串的每个字符作为节点,构建出一棵树,使得查找、插入和删除操作的时间复杂度接近O(1)。 6. **位运算**:位运算是在二进制...

    变位词查询

    首先,我们来看一下如何使用Trie树(字典树)来实现变位词查询。Trie树是一种特殊的树形数据结构,用于存储一个关联数组,其中的键通常是字符串。每个节点代表一个前缀,而叶子节点通常代表完整的关键词。在Trie树中...

    FilterTRS:前缀树Trie的应用

    Trie,又称前缀树或字典树,是一种有序树,用于存储动态集合或关联数组,其中的键通常是字符串。Trie树的主要特点是能够快速查找具有相同前缀的字符串,通过将字符串的每个字符作为节点,构建出一种层次结构。根节点...

    rust_radix_trie:在Rust中实现的快速通用基数trie

    其中,Trie(又称“前缀树”或“字典树”)是一种高效的数据结构,常用于字符串搜索和存储。Rust作为一种系统级编程语言,以其内存安全和高性能特性吸引了众多开发者。本文将深入探讨在Rust中实现的rust_radix_trie...

    字典序相关介绍.zip

    此外,字典序还与字典树(如Trie)紧密相关。字典树是一种数据结构,用于高效地存储和检索字符串集合。在构建字典树时,字典序可以帮助我们决定节点的分支顺序,从而提高查找效率。 总的来说,字典序是计算机科学中...

    常用排序查找算法详解

    最后,"Trie 树",也称为字典树或前缀树,是一种用于字符串查找的树形数据结构。它允许快速查找具有公共前缀的字符串,常用于关键词搜索和自动补全功能。 "LCS 最长公共子序列"虽然不直接属于排序或查找,但它是...

    Hash相关题解1

    这道题同样可以使用哈希函数或者Trie字典树解决,通过在原始字符串上直接处理,减少额外的空间消耗。 4. HDU 2648【基础】 商店价格排名问题可以通过哈希表来快速查找特定商店的价格变化,同时通过排序和二分查找来...

    python刷题day4.1.rar

    字典树(Trie)是一种用于高效存储和检索字符串的数据结构。在Python中,可以使用列表或字典来实现字典树。它允许快速查找、插入和删除字符串,尤其适用于关键词搜索和自动补全功能。 “理论讲解:字典树”(36....

    字典序(Lexicographic Order)是一种按照字典中字母顺序排列的排序方式

    字典序(Lexicographic Order),也称为字典顺序或字面顺序,是计算机科学中一个重要的概念,特别是在字符串处理、排序算法以及数据结构如字典树(Trie)等领域广泛应用。字典序的定义源自于我们查阅字典时按照字母...

    多模式串匹配之AC自动机算法

    1. **字典树(Trie)的构建**:首先构建一个字典树来存储所有的模式字符串。这一步是为了快速定位到模式字符串的关键位置。 2. **失败指针的构造**:构建失败指针以确保在模式匹配过程中不会出现回溯,从而提高效率...

Global site tag (gtag.js) - Google Analytics