字典树Java实现

Trie树的原理

  Trie树也称字典树,因为其效率很高,所以在在字符串查找、前缀匹配等中应用很广泛,其高效率是以空间为代价的。

  利用串构建一个字典树,这个字典树保存了串的公共前缀信息,因此可以降低查询操作的复杂度。下面以英文单词构建的字典树为例,这棵Trie树中每个结点包括26个孩子结点,因为总共有26个英文字母(假设单词都是小写字母组成)。

详细介绍请参考:http://www.cnblogs.com/dolphin0520/archive/2011/10/11/2207886.html 等

字典树模版(Java)

  1 /**
  2  * 字典树模版,默认只包含26个小写字母
  3  * 提供hasStr、insert、countPrefix、preWalk、getRoot接口
  4  * @author 
  5  */
  6 public class TrieTree {
  7 
  8     private final int SIZE = 26;  //每个节点能包含的子节点数,即需要SIZE个指针来指向其孩子
  9     private Node root;   //字典树的根节点
 10 
 11     /**
 12      * 字典树节点类
 13      * @author Lenovo
 14      */
 15     private class Node {
 16         private boolean isStr;   //标识该节点是否为某一字符串终端节点
 17         private int num;         //标识经过该节点的字符串数。在计算前缀包含的时候会用到
 18         private Node[] child;    //该节点的子节点
 19 
 20         public Node() {
 21             child = new Node[SIZE];
 22             isStr = false;
 23             num = 1;
 24         }
 25     }
 26 
 27     public TrieTree() {
 28         root = new Node();
 29     }
 30 
 31     /**
 32      * 检查字典树中是否完全包含字符串word
 33      * @param word
 34      * @return
 35      */
 36     public boolean hasStr(String word) {
 37         Node pNode = this.root;
 38 
 39         //逐个字符去检查
 40         for (int i = 0; i < word.length(); i++) {
 41             int index = word.charAt(i) - 'a';
 42             //在字典树中没有对应的节点,或者word字符串的最后一个字符在字典树中检测对应节点的isStr属性为false,则返回false
 43             if (pNode.child[index] == null
 44                     || (i + 1 == word.length() && pNode.child[index].isStr == false)) {
 45                 return false;
 46             }
 47             pNode = pNode.child[index];
 48         }
 49 
 50         return true;
 51     }
 52 
 53     /**
 54      * 在字典树中插入一个单词
 55      * @param word
 56      */
 57     public void insert(String word) {
 58         if (word == null || word.isEmpty()) {
 59             return;
 60         }
 61         Node pNode = this.root;
 62         for (int i = 0; i < word.length(); i++) {
 63             int index = word.charAt(i) - 'a';
 64             if (pNode.child[index] == null) {   //如果不存在节点,则new一个一节点插入字典树
 65                 Node tmpNode = new Node();
 66                 pNode.child[index] = tmpNode;
 67             } else {
 68                 pNode.child[index].num++;       //如果字典树中改路径上存在节点,则num加1,表示在该节点上有一个新的单词经过
 69             }
 70             pNode = pNode.child[index];
 71         }
 72         pNode.isStr = true;
 73     }
 74 
 75     /**
 76      * 统计在字典树中有多少个单词是以str为前缀的
 77      * @param str
 78      * @return
 79      */
 80     public int countPrefix(String str) {
 81         Node pNode = this.root;
 82         for (int i = 0; i < str.length(); i++) {
 83             int index = str.charAt(i) - 'a';
 84             if (pNode.child[index] == null) {
 85                 return 0;
 86             } else {
 87                 pNode = pNode.child[index];
 88             }
 89         }
 90 
 91         return pNode.num;
 92     }
 93 
 94     /**
 95      * 先序遍历
 96      * @param root
 97      */
 98     public void preWalk(Node root) {
 99         Node pNode = root;
100         for (int i = 0; i < SIZE; i++) {
101             if (pNode.child[i] != null) {
102                 System.out.print((char) ('a' + i) + "--");
103                 preWalk(pNode.child[i]);
104             }
105         }
106     }
107 
108     /**
109      * 返回字典树根节点
110      * @return
111      */
112     public Node getRoot() {
113         return root;
114     }
115 
116 }