赞
踩
Trie,又称字典树、单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
上图是一棵Trie树,表示了关键字集合{“a”, “to”, “tea”, “ted”, “ten”, “i”, “in”, “inn”} 。从上图可以归纳出Trie树的基本性质:
非递归的实现也有两种方式,一种是利用自己创建的节点来实现,具体实现如下:
- public class Trie {
- public static void main(String[] args) {
- Trie trie = new Trie();
- trie.add("apple");
- System.out.println(trie.contains("apple"));
- System.out.println(trie.isPrefix("app"));
- }
- private class TreeNode{
- public boolean isWord;
- public TreeMap<Character,TreeNode> next;
- public TreeNode(){
- this(false);
- next = new TreeMap<>();
- }
- public TreeNode(boolean isWord){
- this.isWord = isWord;
- }
- }
- private TreeNode root;
- private int size;
- public Trie(){
- this.root = new TreeNode();
- this.size = 0;
- }
- public int getSize(){
- return size;
- }
- public void add(String str){
- TreeNode cur = root;
- for(int i=0;i<str.length();i++){
- char c = str.charAt(i);
- if(cur.next.get(c) == null){
- //新建节点
- cur.next.put(c, new TreeNode());
- }
- //否则,就直接走到该节点位置即可
- cur = cur.next.get(c);
- }
- if(!cur.isWord){
- //确定cur是新的单词
- cur.isWord = true;
- size++;
- }
- }
- public boolean contains(String str){
- TreeNode cur = root;
- for(int i=0;i<str.length();i++){
- char c = str.charAt(i);
- if(cur.next.get(c) == null) return false;
- cur = cur.next.get(c);
- }
- return cur.isWord;
- }
- public boolean isPrefix(String prefix){
- TreeNode cur = root;
- for(int i=0;i<prefix.length();i++){
- char c = prefix.charAt(i);
- if(cur.next.get(c) == null) return false;
- cur = cur.next.get(c);
- }
- return true;
- }
-
- }
-
这种实现方式是利用自己创建的节点实现的。每一个Trie对象内部都存在一个TreeNode对象与size对象。其中TreeNode对象内部存在着一个TreeMap,TreeMap内存储着每一个字符与下一个节点的对应关系。
当然,也有另一种实现方式:
- class Trie {
- private Trie[] children;
- private boolean isWord;
- public Trie() {
- children = new Trie[26];
- isWord = false;
- }
-
- public void insert(String word) {
- Trie node = this;
- for(char c : word.toCharArray()){
- int idx = c - 'a';
- if(node.children[idx] == null){
- node.children[idx] = new Trie();
- }
- node = node.children[idx];
- }
- node.isWord = true;
- }
-
- public boolean search(String word) {
- Trie node = searchPrefix(word);
- return node != null && node.isWord;
- }
-
- public boolean startsWith(String prefix) {
- return searchPrefix(prefix) != null;
- }
- public Trie searchPrefix(String word){
- Trie node = this;
- for(char c : word.toCharArray()){
- int idx = c - 'a';
- if(node.children[idx] != null){
- node = node.children[idx];
- }else{
- return null;
- }
- }
- return node;
- }
- }
-
- /**
- * Your Trie object will be instantiated and called as such:
- * Trie obj = new Trie();
- * obj.insert(word);
- * boolean param_2 = obj.search(word);
- * boolean param_3 = obj.startsWith(prefix);
- */
这个实现方式是每一个Trie对象内部存储自己的Trie[]数组,由此实现节点的对应关系。
- public void recursionAdd(String word) {
- Node cur = root;
- add(root, word, 0);
- }
-
- /**
- * 递归写法调用方法实现递归添加
- *
- * @param node 传入要进行添加的节点
- * @param word 传入要进行添加的单词
- */
- public void add(Node node, String word, int index) {
- // 确定终止条件,这个终止条件在没加index这个参数时,很难确定
- // 此时一个单词已经遍历完成了,如果这个结束节点没有标记为单词,就标记为单词
- if (!node.isWord && index == word.length()) {
- node.isWord = true;
- size++;
- }
-
- if (word.length() > index) {
- char addLetter = word.charAt(index);
- // 判断trie的下个节点组中是否有查询的字符,如果没有,就添加
- if (node.next.get(addLetter) == null) {
- node.next.put(addLetter, new Node());
- }
- // 基于已经存在的字符进行下个字符的递归查询
- add(node.next.get(addLetter), word, index + 1);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。