海量数据处理-Trie树
http://blog.csdn.net/beiyeqingteng/article/details/6981263
http://blog.csdn.net/zmazon/article/details/8227610#
關注Trie 這種結構已經很久,Trie有一個很有趣的用途,那就是自動提示。而且,前不久在一次面試里,也需要用Trie來解答。所以,在此對這個數據結構進行總結。
Trie,又稱單詞查找樹或鍵樹,是一種樹形結構。典型應用是用于統計和排序大量的字符串(但不僅限于字符串),所以經常被搜索引擎系統用于文本詞頻統計。它的優點是:最大限度地減少無謂的字符串比較,查詢效率比哈希表高。它有3個基本性質:
1,根節點不包含字符,除根節點外每一個節點都只包含一個字符。
2,從根節點到某一節點,路徑上經過的字符連接起來,為該節點對應的字符串。
3,每個節點的所有子節點包含的字符都不相同。
下面這個圖就是Trie的表示,每一條邊表示一個字符,如果結束,就用星號表示。在這個Trie結構里,我們有下面字符串,比如do, dork, dorm等,但是Trie里沒有ba, 也沒有sen,因為在a, 和n結尾,沒有結束符號(星號)。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
我們來看看Trie樹的特點:根節點為空值,剩下每一個節點保存一個字母。知道這些就夠了!
我們再來看看這棵樹能干什么?如果從根節點遍歷到某一個節點把路徑節點的值連在一起就構成了一個字符串,利用這個特點很容易想到這棵樹的第一個功能能幫我們查找某一個單詞是否在樹中(需要在每一個節點設置一個標志,表示從根節點到此節點是否構成一個單詞);如果該單詞存在,我們可以利用它實現第二個功能:去除重復單詞;同樣如果該詞存,在我們還可以看出它的第三個功能:統計單詞頻率;因為這是一個樹形結構我們利用這個特點很容易看出它的第四個功能能幫我們查找N個單詞的最長公共前綴;如果我們按順序遍歷輸出整棵樹,發現它的第五個功能:對字符串排序。
這棵樹創建看起來比較容易,就有一個問題需要我們考慮:父節點如何保存孩子節點? 主要有兩種方式供大家參考:
1.因為是英文字符,我們可以用Node[26]來保存孩子節點(如果是數字我們可以用Node[10]),這種方式最快,但是并不是所有節點都會有很多孩子,所以這種方式浪費的空間太多
2.用一個鏈表根據需要動態添加節點。這樣我們就可以省下不小的空間,但是缺點是搜索的時候需要遍歷這個鏈表,增加了時間復雜度。
class TrieNode{//結點類private static final int NUMBER = 26;private char _value;private boolean _isWord;//從根節點到這個節點存不存在一個單詞TrieNode[] _children = new TrieNode[NUMBER];//子結點集合public TrieNode(char c) {this.setValue(c);}public char getValue() {return _value;}public void setValue(char _value) {this._value = _value;}public boolean isWord() {return _isWord;}public void setIsWord(boolean _isWord) {this._isWord = _isWord;}}public class TrieTree {static String[] _words = {"add","am","good","the","think"};//待插入單詞private boolean searchWord(TrieNode _root, String _word) {if(null == _root || null == _word || "".equals(_word))return false;char[] cs = _word.toCharArray();//將字符串轉化為字符數組for(int i = 0; i < cs.length; i++){int index;if(cs[i] >= 'A' && cs[i] <= 'Z'){index = cs[i]-'A';}else if(cs[i] >= 'a' && cs[i] <= 'z') index = cs[i] - 'a';elsereturn false;TrieNode child_node = _root._children[index];if(null != child_node){//找到相同字符if(child_node.isWord())//如果找到該單詞return true;} if(null == child_node)//如果在i層沒找到相同字符 return false;_root = child_node;//重設根節點}return false;}private void insertIntoTree(TrieNode _root, String _word) {//插入一個單詞if(null == _root || null == _word || "".equals(_word))return;char[] cs = _word.toCharArray();//將字符串轉化為字符數組for(int i = 0; i < cs.length; i++){int index;//對應的索引值if(cs[i] >= 'A' && cs[i] <= 'Z'){index = cs[i]-'A';}else if(cs[i] >= 'a' && cs[i] <= 'z') index = cs[i] - 'a';elsereturn;TrieNode child_node = _root._children[index];if(null == child_node){//如果沒找到TrieNode new_node = new TrieNode(cs[i]);//創建新節點if(i == cs.length-1)//如果遍歷到該單詞最后一個字符new_node.setIsWord(true);//把該單詞存在樹中_root._children[index] = new_node;//連接該節點_root = new_node;}else_root = child_node;//更新樹根}}private void printTree(TrieNode _root,char[] _word,int index) {if(_root == null)return;if(_root.isWord()){//如果根節點到此節點構成一個單詞則輸出for(char c : _word){if(c != ' ')System.out.print(c);}System.out.println();}for(TrieNode node : _root._children){//遍歷樹根孩子節點if(node != null){//回溯法遍歷該樹_word[index++] = node.getValue();printTree(node,_word,index);_word[index] = ' ';index--;}}}public static void main(String[] args){TrieTree _tree = new TrieTree();//創建一棵樹TrieNode _root = new TrieNode(' ');//創建根節點for(String word : _words)//插入單詞_tree.insertIntoTree(_root,word);char[] _word = new char[20];_tree.printTree(_root,_word,0);//打印樹中單詞boolean status = _tree.searchWord(_root,"think");//查詢樹中是否存在某單詞System.out.println(status);} }
總結
以上是生活随笔為你收集整理的海量数据处理-Trie树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 寻找数组中最小的k个数(快排和堆排)
- 下一篇: Android Studio的gradl