Trie树-Java实现

41 篇文章 0 订阅
这篇博客探讨了如何使用Trie树解决数据存储和查找问题,特别是在处理大量词汇数据时。通过Java代码展示了Trie树的插入、查找、遍历和实现单词联想功能,以应对如查找高频词等挑战。
摘要由CSDN通过智能技术生成

刷leetcode时候,经常碰见有使用Trie的,其意思就是字典树,

一组单词,inn, int, at, age, adv, ant, 我们可以得到下面的Trie:


当遇到一种问题,比如“ 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。” 该如何解决? 有一种方案就是使用Trie树加 排序实现。

以下代码用Java实现插入、查找、遍历、单词联想(找公共前缀)/**

package jdkproxy;

import java.util.HashMap;

public class Trie_Tree {
	public  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() {
		// HashMap<String, Integer> map=new HashMap<String, Integer>();

		return preTraversal(this.root, "");
	}

	/**
	 * 前序遍历。。。
	 * 
	 * @param root
	 *            子树根节点
	 * @param prefixs
	 *            查询到该节点前所遍历过的前缀
	 * @return
	 */
	private HashMap<String, Integer> preTraversal(Node root, String prefixs) {
		HashMap<String, Integer> map = new HashMap<String, Integer>();

		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) {
		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);
	}
	
	/*test*/
	public static void main(String args[]) // Just used for test
	{
		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 ");
		}

	}
}
class Node {
	public  int dumpli_num; 该字串的重复数目, 该属性统计重复次数的时候有用,取值为0、1、2、3、4、5……
	public int prefix_num;/// 以该字串为前缀的字串数, 应该包括该字串本身!!!!!
	public Node childs[]; 此处用数组实现,当然也可以map或list实现以节省空间
	public boolean isLeaf;/// 是否为单词节点

	public Node() {
		dumpli_num = 0;
		prefix_num = 0;
		isLeaf = false;
		childs = new Node[26];
	}
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Trie字典Java代码实现可以分为以下几部分: 1. 定义Trie节点类,包含children数组和isEndOfWord标识,用于表示是否是单词的结尾。 2. 定义Trie类,包含插入、查找和删除操作。 3. 在Trie类中实现插入操作,遍历字符串每一个字符,在Trie中寻找对应节点,如果不存在则新建节点。 4. 在Trie类中实现查找操作,遍历字符串每一个字符,在Trie中寻找对应节点,如果找到最后一个字符对应的节点的isEndOfWord标识为true,则说明字符串是单词。 5. 在Trie类中实现删除操作,遍历字符串每一个字符,在Trie中寻找对应节点,如果找到最后一个字符对应的节点的isEndOfWord标识为true,则将其设为false,并删除空节点。 如果需要完整代码和注释请告诉我。 ### 回答2: Trie(字典)是一种常用的数据结构,用于高效地存储和查找字符串。下面是Trie字典Java代码实现,用于返回单词。 ```java class TrieNode { private TrieNode[] children; private boolean isEndOfWord; public TrieNode() { children = new TrieNode[26]; // 字母表的大小为26 isEndOfWord = false; } public void insert(String word) { TrieNode curr = this; for (char c : word.toCharArray()) { if (curr.children[c - 'a'] == null) { curr.children[c - 'a'] = new TrieNode(); } curr = curr.children[c - 'a']; } curr.isEndOfWord = true; } public boolean search(String word) { TrieNode node = searchPrefix(word); return node != null && node.isEndOfWord; } public boolean startsWith(String prefix) { TrieNode node = searchPrefix(prefix); return node != null; } private TrieNode searchPrefix(String prefix) { TrieNode curr = this; for (char c : prefix.toCharArray()) { if (curr.children[c - 'a'] == null) { return null; } curr = curr.children[c - 'a']; } return curr; } } public class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } public void insert(String word) { root.insert(word); } public boolean search(String word) { return root.search(word); } public boolean startsWith(String prefix) { return root.startsWith(prefix); } } public class Main { public static void main(String[] args) { Trie trie = new Trie(); trie.insert("apple"); trie.insert("app"); System.out.println(trie.search("apple")); // 输出:true System.out.println(trie.startsWith("app")); // 输出:true System.out.println(trie.search("banana")); // 输出:false } } ``` 以上代码中,`TrieNode`表示Trie的节点,`Trie`表示Trie的结构。其中`TrieNode`类包含了插入单词、查找单词(完全匹配)以及查找前缀的功能。`Trie`类则是对外提供插入、查找单词和前缀的方法。 在`main`方法中,我们演示了如何使用`Trie`类来插入和查找单词。首先,我们插入了两个单词"apple"和"app"。然后分别调用`search`方法来查找"apple"和"banana",以及`startsWith`方法来查找以"app"开头的单词。最后,打印出对应的结果,即是否找到了对应的单词或前缀。 以上是Trie字典Java代码实现,用于返回单词。 ### 回答3: Trie字典是一种经典的数据结构,用于高效地存储和查找字符串集合。下面是一个基于JavaTrie字典的代码实现,可以实现返回单词的功能: ```java class TrieNode { private final int ALPHABET_SIZE = 26; private TrieNode[] children; private boolean isEndOfWord; public TrieNode() { children = new TrieNode[ALPHABET_SIZE]; isEndOfWord = false; } } class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } public void insert(String word) { TrieNode current = root; for (int i = 0; i < word.length(); i++) { char ch = word.charAt(i); int index = ch - 'a'; if (current.children[index] == null) { current.children[index] = new TrieNode(); } current = current.children[index]; } current.isEndOfWord = true; } public boolean search(String word) { TrieNode current = root; for (int i = 0; i < word.length(); i++) { char ch = word.charAt(i); int index = ch - 'a'; if (current.children[index] == null) { return false; } current = current.children[index]; } return current != null && current.isEndOfWord; } public List<String> getAllWords() { List<String> result = new ArrayList<>(); TrieNode current = root; StringBuilder sb = new StringBuilder(); getAllWordsUtil(current, sb, result); return result; } private void getAllWordsUtil(TrieNode node, StringBuilder sb, List<String> result) { if (node == null) { return; } if (node.isEndOfWord) { result.add(sb.toString()); } for (int i = 0; i < ALPHABET_SIZE; i++) { if (node.children[i] != null) { sb.append((char)('a' + i)); getAllWordsUtil(node.children[i], sb, result); sb.deleteCharAt(sb.length() - 1); } } } } public class Main { public static void main(String[] args) { Trie trie = new Trie(); String[] words = {"hello", "world", "java", "programming"}; for (String word : words) { trie.insert(word); } List<String> allWords = trie.getAllWords(); System.out.println("All words in trie: " + allWords); } } ``` 上述代码中,TrieNode类表示字典的节点,包括一个指向子节点的数组和一个标记,用于表示节点是否是某个单词的结尾。Trie类封装了字典的操作,包括插入单词、查找单词和返回所有单词的功能。在代码的主函数中,我们创建一个Trie对象并插入一些单词,然后调用getAllWords()方法返回字典中的所有单词。最后,打印出返回的单词列表。 希望以上解答对您有所帮助,如有更多疑问,请继续追问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值