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  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章