Trie樹就是字典樹,其核心思想就是空間換時間。


舉個簡單的例子。


給你100000個長度不超過10的單詞。對于每一個單詞,我們要判斷他出沒出現(xiàn)過,如果出現(xiàn)了,第一次出現(xiàn)第幾個位置。
這題當(dāng)然可以用hash來,但是我要介紹的是trie樹。在某些方面它的用途更大。比如說對于某一個單詞,我要詢問它的前綴是否出現(xiàn)過。這樣hash就不好搞了,而用trie還是很簡單。
現(xiàn)在回到例子中,如果我們用最傻的方法,對于每一個單詞,我們都要去查找它前面的單詞中是否有它。那么這個算法的復(fù)雜度就是O(n^2)。顯然對于100000的范圍難以接受。現(xiàn)在我們換個思路想。假設(shè)我要查詢的單詞是abcd,那么在他前面的單詞中,以b,c,d,f之類開頭的我顯然不必考慮。而只要找以a開頭的中是否存在abcd就可以了。同樣的,在以a開頭中的單詞中,我們只要考慮以b作為第二個字母的……這樣一個樹的模型就漸漸清晰了……
假設(shè)有b,abc,abd,bcd,abcd,efg,hii這6個單詞,我們構(gòu)建的樹就是這樣的。

對于每一個節(jié)點,從根遍歷到他的過程就是一個單詞,如果這個節(jié)點被標(biāo)記為紅色,就表示這個單詞存在,否則不存在。
那么,對于一個單詞,我只要順著他從跟走到對應(yīng)的節(jié)點,再看這個節(jié)點是否被標(biāo)記為紅色就可以知道它是否出現(xiàn)過了。把這個節(jié)點標(biāo)記為紅色,就相當(dāng)于插入了這個單詞。
這樣一來我們詢問和插入可以一起完成,所用時間僅僅為單詞長度,在這一個樣例,便是10。
我們可以看到,trie樹每一層的節(jié)點數(shù)是26^i級別的。所以為了節(jié)省空間。我們用動態(tài)鏈表,或者用數(shù)組來模擬動態(tài)。空間的花費,不會超過單詞數(shù)×單詞長度。

 

給出一個用類封裝的字典樹代碼,厄。。。做ACM的模板用另一個。。應(yīng)該放在了“ACM模板”文件夾下了。。。

#include <cstdio>
#include 
<iostream>
#include 
<cstring>
using namespace std;


const int num_chars = 26;


class Trie {
public:
      Trie():root(NULL)
{};
      Trie(Trie
& tr);

     
int search(const char* word, char* entry ) const;
     
int insert(const char* word, const char* entry);
     
int remove(const char* word, char* entry);
private:
     
struct Trie_node
     
{
         
char* data;
          Trie_node
* branch[num_chars];
          Trie_node();
     }
* root;
}
;
Trie::Trie_node::Trie_node() 
{
      data 
= NULL;
    
for (int i=0; i<num_chars; ++i) 
          branch[i] 
= NULL;
}


int Trie::search(const char* word, char* entry ) const 
{
    
int position = 0;
    
char char_code;
     Trie_node 
*location = root;
    
while( location!=NULL && *word!=0 ) 
    
{
        
if (*word>='A' && *word<='Z'
              char_code 
= *word-'A';
        
else if (*word>='a' && *word<='z'
              char_code 
= *word-'a';
        
else return 0;


         location 
= location->branch[char_code];
         position
++;
         word
++;
    }

    
if ( location != NULL && location->data != NULL ) 
    
{
        strcpy(entry,location
->data);
        
return 1;
    }

    
else return 0;
}

int Trie::insert(const char* word, const char* entry) 
{
    
int result = 1, position = 0;
    
if ( root == NULL ) root = new Trie_node;
    
char char_code;
      Trie_node 
*location = root;
    
while( location!=NULL && *word!=0 )
    
{
        
if (*word>='A' && *word<='Z'
              char_code 
= *word-'A';
        
else if (*word>='a' && *word<='z'
              char_code 
= *word-'a';
        
else return 0;


        
if( location->branch[char_code] == NULL ) 
              location
->branch[char_code] = new Trie_node;


          location 
= location->branch[char_code];
          position
++;
          word
++;
    }

    
if (location->data != NULL)
          result 
= 0;
    
else {
          location
->data = new char[strlen(entry)+1];
        strcpy(location
->data, entry);
    }

    
return result;
}

int main()
{
      Trie t;
      
char entry[100];
      t.insert(
"aa""DET"); 
      t.insert(
"abacus","NOUN");
      t.insert(
"abalone","NOUN"); 
      t.insert(
"abandon","VERB");
      t.insert(
"abandoned","ADJ"); 
      t.insert(
"abashed","ADJ");
      t.insert(
"abate","VERB"); 
      t.insert(
"this""PRON");
    
if (t.search("this", entry))
        cout
<<"'this' was found. pos: "<<entry<<endl;
    
if (t.search("abate", entry))
        cout
<<"'abate' is found. pos: "<<entry<<endl;
    
if (t.search("baby", entry))
        cout
<<"'baby' is found. pos: "<<entry<<endl;
    
else
        cout
<<"'baby' does not exist at all!"<<endl;
    
    
if (t.search("aa", entry))
        cout
<<"'aa was found. pos: "<<entry<<endl;
}



PS:實現(xiàn)方法http://met.fzu.edu.cn/eduonline/web/web/resources/articleContent.asp?id=346