轉載 http://blog.csdn.net/beiyetengqing/article/details/7856113
關注Trie 這種結構已經很久,Trie有一個很有趣的用途,那就是自動提示。而且,前不久在一次面試裡,也需要用Trie來解答。所以,在此對這個資料結構進行總結。
Trie,又稱單詞尋找樹或鍵樹,是一種樹形結構。典型應用是用於統計和排序大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文本詞頻統計。它的優點是:最大限度地減少無謂的字串比較,查詢效率比雜湊表高。
它有3個基本性質:
- 根節點不包含字元,除根節點外每一個節點都只包含一個字元。
- 從根節點到某一節點,路徑上經過的字元串連起來,為該節點對應的字串。
- 每個節點的所有子節點包含的字元都不相同。
下面這個圖就是Trie的表示,每一條邊表示一個字元,如果結束,就用星號表示。在這個Trie結構裡,我們有下面字串,比如do, dork, dorm等,但是Trie裡沒有ba, 也沒有sen,因為在a, 和n結尾,沒有結束符號(星號)。
有了這樣一種資料結構,我們可以用它來儲存一個字典,要查詢改字典裡是否有相應的詞,是否非常的方便呢?我們也可以做智能提示,我們把使用者已經搜尋的詞存在Trie裡,每當使用者輸入一個詞的時候,我們可以自動提示,比如當使用者輸入 ba, 我們會自動提示 bat 和 baii.
現在來討論Trie的實現。
首先,我們定義一個Abstract Trie,Trie 裡存放的是一個Node。這個類裡有兩個操作,一個是插入,另一個是查詢。具體實現放在後面。
Node 類的實現
[java] view plaincopy
- class Node {
- char content; // the character in the node
- boolean isEnd; // whether the end of the words
- int count; // the number of words sharing this character
- LinkedList<Node> childList; // the child list
-
- public Node(char c){
- childList = new LinkedList<Node>();
- isEnd = false;
- content = c;
- count = 0;
- }
-
- public Node subNode(char c){
- if(childList != null){
- for(Node eachChild : childList){
- if(eachChild.content == c){
- return eachChild;
- }
- }
- }
- return null;
- }
- }
現在我們來看這個Trie類的具體實現。
[java] view plaincopy
- public class Trie{
- private Node root;
-
- public Trie(){
- root = new Node(' ');
- }
-
- public void insert(String word){
- if(search(word) == true) return;
-
- Node current = root;
- for(int i = 0; i < word.length(); i++){
- Node child = current.subNode(word.charAt(i));
- if(child != null){
- current = child;
- } else {
- current.childList.add(new Node(word.charAt(i)));
- current = current.subNode(word.charAt(i));
- }
- current.count++;
- }
- // Set isEnd to indicate end of the word
- current.isEnd = true;
- }
- public boolean search(String word){
- Node current = root;
-
- for(int i = 0; i < word.length(); i++){
- if(current.subNode(word.charAt(i)) == null)
- return false;
- else
- current = current.subNode(word.charAt(i));
- }
- /*
- * This means that a string exists, but make sure its
- * a word by checking its 'isEnd' flag
- */
- if (current.isEnd == true) return true;
- else return false;
- }
-
- public void deleteWord(String word){
- if(search(word) == false) return;
-
- Node current = root;
- for(char c : word.toCharArray()) {
- Node child = current.subNode(c);
- if(child.count == 1) {
- current.childList.remove(child);
- return;
- } else {
- child.count--;
- current = child;
- }
- }
- current.isEnd = false;
- }
-
- public static void main(String[] args) {
- Trie trie = new Trie();
- trie.insert("ball");
- trie.insert("balls");
- trie.insert("sense");
-
- // testing deletion
- System.out.println(trie.search("balls"));
- System.out.println(trie.search("ba"));
- trie.deleteWord("balls");
- System.out.println(trie.search("balls"));
- System.out.println(trie.search("ball"));
- }
- }
時間複雜度分析:
對於insert, 如果被插入的String長度是 k, 每對一個字元進行查詢,我們最多在child linkedlist裡面查詢26次(最多26個字母),所以,複雜度為O(26*k) = O(k). 對於 search, 複雜度是一樣的。
本文代碼來自:http://www.technicalypto.com/2010/04/trie-in-java.html