Trie 树 及Java实现

来源于英文“retrieval”.   Trie树就是字符树,其核心思想就是空间换时间。

举个简单的例子。
   给你100000个长度不超过10的单词。对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。
这题当然可以用hash来,但是我要介绍的是trie树。在某些方面它的用途更大。比如说对于某一个单词,我要询问它的前缀是否出现过。这样hash就不好搞了,而用trie还是很简单。

   现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否有它。那么这个算法的复杂度就是O(n^2)。显然对于100000的范围难以接受。现在我们换个思路想。假设我要查询的单词是abcd,那么在他前面的单词中,以b,c,d,f之类开头的我显然不必考虑。而只要找以a开头的中是否存在abcd就可以了。同样的,在以a开头中的单词中,我们只要考虑以b作为第二个字母的……这样一个树的模型就渐渐清晰了……

   我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。(转自一大牛)

Trie树的java代码 实现如下:

Java代码   收藏代码
  1. import java.util.ArrayList;  
  2. import java.util.Iterator;  
  3. import java.util.List;  
  4.   
  5.   
  6. /** *//** 
  7.  * A word trie which can only deal with 26 alphabeta letters. 
  8.  * @author Leeclipse 
  9.  * @since 2007-11-21 
  10.  */  
  11.   
  12. public class Trie{  
  13.    
  14.    private Vertex root;//一个Trie树有一个根节点  
  15.   
  16.     //内部类  
  17.     protected class Vertex{//节点类  
  18.         protected int words;  
  19.         protected int prefixes;  
  20.         protected Vertex[] edges;//每个节点包含26个子节点(类型为自身)  
  21.         Vertex() {  
  22.             words = 0;  
  23.             prefixes = 0;  
  24.             edges = new Vertex[26];  
  25.             for (int i = 0; i < edges.length; i++) {  
  26.                 edges[i] = null;  
  27.             }  
  28.         }  
  29.     }  
  30.   
  31.     
  32.     public Trie () {  
  33.         root = new Vertex();  
  34.     }  
  35.   
  36.      
  37.     /** *//** 
  38.      * List all words in the Trie. 
  39.      *  
  40.      * @return 
  41.      */  
  42.   
  43.     public List< String> listAllWords() {  
  44.          
  45.         List< String> words = new ArrayList< String>();  
  46.         Vertex[] edges = root.edges;  
  47.          
  48.         for (int i = 0; i < edges.length; i++) {  
  49.             if (edges[i] != null) {  
  50.                      String word = "" + (char)('a' + i);  
  51.                 depthFirstSearchWords(words, edges[i], word);  
  52.             }  
  53.         }          
  54.         return words;  
  55.     }  
  56.   
  57.      /** *//** 
  58.      * Depth First Search words in the Trie and add them to the List. 
  59.      *  
  60.      * @param words 
  61.      * @param vertex 
  62.      * @param wordSegment 
  63.      */  
  64.   
  65.     private void depthFirstSearchWords(List words, Vertex vertex, String wordSegment) {  
  66.         Vertex[] edges = vertex.edges;  
  67.         boolean hasChildren = false;  
  68.         for (int i = 0; i < edges.length; i++) {  
  69.             if (edges[i] != null) {  
  70.                 hasChildren = true;  
  71.                 String newWord = wordSegment + (char)('a' + i);                  
  72.                 depthFirstSearchWords(words, edges[i], newWord);  
  73.             }              
  74.         }  
  75.         if (!hasChildren) {  
  76.             words.add(wordSegment);  
  77.         }  
  78.     }  
  79.   
  80.     public int countPrefixes(String prefix) {  
  81.         return countPrefixes(root, prefix);  
  82.     }  
  83.   
  84.     private int countPrefixes(Vertex vertex, String prefixSegment) {  
  85.         if (prefixSegment.length() == 0) { //reach the last character of the word  
  86.             return vertex.prefixes;  
  87.         }  
  88.   
  89.         char c = prefixSegment.charAt(0);  
  90.         int index = c - 'a';  
  91.         if (vertex.edges[index] == null) { // the word does NOT exist  
  92.             return 0;  
  93.         } else {  
  94.   
  95.             return countPrefixes(vertex.edges[index], prefixSegment.substring(1));  
  96.   
  97.         }          
  98.   
  99.     }  
  100.   
  101.     public int countWords(String word) {  
  102.         return countWords(root, word);  
  103.     }      
  104.   
  105.     private int countWords(Vertex vertex, String wordSegment) {  
  106.         if (wordSegment.length() == 0) { //reach the last character of the word  
  107.             return vertex.words;  
  108.         }  
  109.   
  110.         char c = wordSegment.charAt(0);  
  111.         int index = c - 'a';  
  112.         if (vertex.edges[index] == null) { // the word does NOT exist  
  113.             return 0;  
  114.         } else {  
  115.             return countWords(vertex.edges[index], wordSegment.substring(1));  
  116.   
  117.         }          
  118.   
  119.     }  
  120.   
  121.       
  122.     /** *//** 
  123.      * Add a word to the Trie. 
  124.      *  
  125.      * @param word The word to be added. 
  126.      */  
  127.   
  128.     public void addWord(String word) {  
  129.         addWord(root, word);  
  130.     }  
  131.   
  132.       
  133.     /** *//** 
  134.      * Add the word from the specified vertex. 
  135.      * @param vertex The specified vertex. 
  136.      * @param word The word to be added. 
  137.      */  
  138.   
  139.     private void addWord(Vertex vertex, String word) {  
  140.        if (word.length() == 0) { //if all characters of the word has been added  
  141.             vertex.words ++;  
  142.         } else {  
  143.             vertex.prefixes ++;  
  144.             char c = word.charAt(0);  
  145.             c = Character.toLowerCase(c);  
  146.             int index = c - 'a';  
  147.             if (vertex.edges[index] == null) { //if the edge does NOT exist  
  148.                 vertex.edges[index] = new Vertex();  
  149.             }  
  150.   
  151.             addWord(vertex.edges[index], word.substring(1)); //go the the next character  
  152.         }  
  153.     }  
  154.   
  155.     public static void main(String args[])  //Just used for test  
  156.     {  
  157.     Trie trie = new Trie();  
  158.     trie.addWord("China");  
  159.     trie.addWord("China");  
  160.     trie.addWord("China");  
  161.   
  162.     trie.addWord("crawl");  
  163.     trie.addWord("crime");  
  164.     trie.addWord("ban");  
  165.     trie.addWord("China");  
  166.   
  167.     trie.addWord("english");  
  168.     trie.addWord("establish");  
  169.     trie.addWord("eat");  
  170.     System.out.println(trie.root.prefixes);  
  171.      System.out.println(trie.root.words);  
  172.   
  173.   
  174.      
  175.      List< String> list = trie.listAllWords();  
  176.      Iterator listiterator = list.listIterator();  
  177.        
  178.      while(listiterator.hasNext())  
  179.      {  
  180.           String s = (String)listiterator.next();  
  181.           System.out.println(s);  
  182.      }  
  183.   
  184.      
  185.      int count = trie.countPrefixes("ch");  
  186.      int count1=trie.countWords("china");  
  187.      System.out.println("the count of c prefixes:"+count);  
  188.      System.out.println("the count of china countWords:"+count1);  
  189.   
  190.    
  191.     }  
  192. }  
  193. 运行:  
  194. C:\test>java   Trie  
  195. 10  
  196. 0  
  197. ban  
  198. china  
  199. crawl  
  200. crime  
  201. eat  
  202. english  
  203. establish  
  204. the count of c prefixes:4  
  205. the count of china countWords:4  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值