標準trie樹的Java實現

        trie樹也叫字典樹,網上各種資料和解釋都是說它的效率比哈希表要高,在這裏我先不做說明和比較,在後續的文章中我會對哈希算法、哈希表、hashmap都會有介紹,這裏主要是搞清楚這個trie樹的基本原理和具體實現。

       trie樹的基本原理就是拿空間來換時間,什麼個意思呢,現在以幾個英文單詞爲例,"abc","abcde","acd","ecd",我想要去查找他們,最原始的辦法就是在字典取到所有的單詞,再利用字符串匹配(這個的具體實現就比較多了)。很明顯在字符串匹配的那一塊將是癥結所在,原理都是將字符串拆成一個個的字符,再去兩兩匹配,可以想象如果不對存放單詞的那個庫進行結構化那將是多麼巨大的災難,而trie樹就是用來優化字典的結構。還以英文單詞爲例,再怎麼複雜的單詞都是由26個字母組成的,只不過是在長度和排列順序上不一樣而已,那就好辦了,不就是匹配麼,說穿了就是從單詞的第一個字母開始,一個接着一個第往下找,那我就建一個數一樣的結構,分層來處理不就OK了?trie樹的基本原理就是這樣。先創建一個根節點,什麼都不幹,就是相當於一個頭指針的作用,然後第一層就是放單詞的首字母,接下來再在每一個首字母節點下面同樣操作,一次錄入直到單詞完結,那麼問題來了我怎麼確定到哪是一個單詞,簡單,在該處存一個變量做判斷不就完事,如下圖(從網上copy得到):


     至此,我們可以得到一個trie樹的最核心的結構trieNode它至少要有這麼幾個屬性,自己本身的值value,自己下面的子節點 sons和判斷該處是否是一個單詞的結尾isEnd,有了這個之後後面的事情就簡單了。具體java代碼如下:

<span style="font-size:14px;">package TrieTree;
public class myTrie {
    private int CHAR_SIZE=26;//由於這裏是先做英文匹配,共26個英文字母
    private TrieNode root;//根節點,不存儲任何數據,相當於一個頭指針
    public myTrie() {
        root=new TrieNode();
    }
    //插入一個單詞
    public  void insertWord(String word){
        if(word==null||word.trim().equals("")){
            return ;
        }
        //1.轉換成小寫
        word=word.toLowerCase();
        //2.轉換成字符數據
        char [] letters=word.toCharArray();
        //3.開始插入
        TrieNode node=root;
        for(int i=0;i<letters.length;i++){
            int pos=letters[i]-'a';//確定每一個字符在數組中的位置
            if(node.sons[pos]==null){
                TrieNode td=new TrieNode();
                td.value=letters[i];
                node.sons[pos]=td;
            }else{
                node.sons[pos].num++;
            }
            node=node.sons[pos];
        }
        node.isEnd=true;
    }
    //匹配一個單詞
    public boolean findWord(String word){
        if(word==null||word.trim().equals("")){
            return false;
        }
        word=word.trim().toLowerCase();
        TrieNode node=root;
        char[] letters=word.toCharArray();
        for(int i=0;i<letters.length;i++){
            int pos=letters[i]-'a';
            if(node.sons[pos]==null){
                return false;
            }else{
                node=node.sons[pos];
            }
        }
        return node.isEnd;
    }
    //構建樹的節點類
    private class TrieNode{
        private int num;//記錄通過該節點的數目
        private TrieNode [] sons;//子節點
        private char value;//該處節點的值
        private boolean isEnd;//標記是否是一個單詞的結尾
        public TrieNode() {
            num=1;
            sons=new TrieNode[CHAR_SIZE];
            isEnd=false;
        }
    }
}</span>

其中num屬性主要是用來統計單詞前綴的,這裏面沒有做寫其他的方法,諸如遍歷等;還有這裏是進行英文匹配,中文匹配原理是一樣的,但中文的單字有幾萬個,如果每一個節點都分配那麼多的空間是不現實的,所以一種解決方法是每一個字開頭組成一棵樹,再將所有的樹彙集成森林存在磁盤裏面;由於中文的詞語比較短很少有5個以上的所以樹的高度不高,主要消耗在內部的匹配。

     關於trie樹的效率以及和其他樹的比較在這裏不詳細討論,後面會陸續討論其他幾種,然後再去做具體的 比較




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