Trie 字典树

资料来源:http://www.cppblog.com/abilitytao/archive/2009/04/21/80598.html

Trie, 又称字典树、单词查找树,是一种树形结构,用于保存大量的字符串。它的优点是:利用字符串的公共前缀来节约存储空间。相对来说,Trie树是一种比较简单的数据结构.理解起来比较简单,正所谓简单的东西也得付出代价.故Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.其基本性质可以归纳为:

1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。

2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。

3. 每个节点的所有子节点包含的字符都不相同。

其基本操作有:查找 插入和删除,当然删除操作比较少见.我在这里只是实现了对整个树的删除操作,至于单个word的删除操作也很简单.

搜索字典项目的方法为:

(1) 从根结点开始一次搜索;

(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;

(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。

(4) 迭代过程……

(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。其他操作类似处理.

 

隐藏行号 复制代码 Demo
  1. /*
    
  2. Name: Trie???????????? 
    
  3. Author: MaiK 
    
  4. Description: Trie???????????? ,???????? ??????????????
    
  5. */
    
  6.  
  7. #include
         
         
    
         
         
  8. #include
         
         
          
          using namespace std;
    
         
         
  9. const int sonnum=26, base='a';
    
  10. struct Trie{    
    
  11.     int num;                  //to remember how many word can reach here,that is to say,prefix    
    
  12.     bool terminal;            //If terminal==true ,the current point has no following point    
    
  13.     struct Trie *son[sonnum]; //the following point
    
  14.     };
    
  15. Trie *NewTrie() // create a new node
    
  16. {    
    
  17.     Trie *temp=new Trie;        temp->num=1;
    
  18.     temp->terminal=false;    
    
  19.     for(int i=0;i
         
         
  20.         temp->son[i]=NULL;    
    
  21.     return temp;
    
  22. }
    
  23.  
  24. void Insert(Trie *pnt,char *s,int len) // insert a new word to Trie tree
    
  25. {    
    
  26.     Trie *temp=pnt;
    
  27.     for(int i=0;i
         
         
  28.     {        
    
  29.         if(temp->son[s[i]-base]==NULL)
    
  30.             temp->son[s[i]-base]=NewTrie();        
    
  31.         else 
    
  32.             temp->son[s[i]-base]->num++;        
    
  33.         temp=temp->son[s[i]-base];    
    
  34.     }        temp->terminal=true;
    
  35. }
    
  36.  
  37. void Delete(Trie *pnt) // delete the whole tree
    
  38. {    
    
  39.     if(pnt!=NULL)     
    
  40.     {        
    
  41.         for(int i=0; i
         
         
    
          
          
    •             if(pnt->son[i]!=NULL)
      
    •                 Delete(pnt->son[i]);        
      
    •         delete pnt;         
      
    •         pnt=NULL;    
      
    •     }
      
    • }
      
    • 
      
    • Trie* Find(Trie *pnt,char *s,int len) //trie to find the current word
      
    • {    
      
    •     Trie *temp=pnt;    
      
    •     for(int i=0;i
              
              
    •         if(temp->son[s[i]-base]!=NULL)
      
    •             temp=temp->son[s[i]-base];        
      
    •         else 
      
    •             return NULL;    
      
    •     return temp;
      
    • } 
      

 

 

以下资料来源:http://blog.chinaunix.net/u2/65170/showart_1073487.html <script language="javascript"> function CopyCode(key){var codeElement=null;var trElements=document.all.tags("ol");var i;for(i=0;i

 

隐藏行号 复制代码 Demo
  1. // trie.cpp : ????????????????????????????
    
  2.  
  3.  
  4. #include 
         
         
    
         
         
  5. #include 
         
         
    
         
         
  6. //#include 
         
         
    
         
         
  7.  
  8.  
  9. #include 
         
         
    
         
         
  10. using namespace std;
    
  11. const int num_chars = 26;
    
  12. class Trie {
    
  13. public:
    
  14.        Trie();
    
  15.        Trie(Trie& tr);
    
  16.      virtual ~Trie();
    
  17.      int trie_search(const char* word, char* entry ) const;
    
  18.      int insert(const char* word, const char* entry);
    
  19.      int remove(const char* word, char* entry);
    
  20. protected:
    
  21.      struct Trie_node
    
  22.      {
    
  23.            char* data; //????????????????root???????????????????? 
    
  24.  
  25.            Trie_node* branch[num_chars]; //???? 
    
  26.  
  27.            Trie_node(); //???????? 
    
  28.  
  29.      };
    
  30.      
    
  31.        Trie_node* root; //??????(????) 
    
  32.  
  33. };
    
  34. Trie::Trie_node::Trie_node() 
    
  35. {
    
  36.       data = NULL;
    
  37.     for (int i=0; i
         
         
    
          
          
    •           branch[i] = NULL;
      
    • }
      
    • Trie::Trie():root(NULL)
      
    • {
      
    • }
      
    • Trie::~Trie()
      
    • {
      
    • }
      
    • int Trie::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); //??data???????????????? 
      
    • 
      
    •     }
      
    •     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.trie_search("this", entry))
      
    •         cout<<"'this' was found. pos: "<
              
              
               
               <
               
               
              
              
    •     if (t.trie_search("abate", entry))
      
    •         cout<<"'abate' is found. pos: "<
              
              
               
               <
               
               
              
              
    •     if (t.trie_search("baby", entry))
      
    •         cout<<"'baby' is found. pos: "<
              
              
               
               <
               
               
              
              
    •     else
      
    •         cout<<"'baby' does not exist at all!"<
              
              
    •     
      
    •     if (t.trie_search("aa", entry))
      
    •         cout<<"'aa was found. pos: "<
              
              
               
               <
               
               
              
              
    •     system("pause");
      
    • }
      
    • 
      
<script language="javascript"> function CopyCode(key){var codeElement=null;var trElements=document.all.tags("ol");var i;for(i=0;i  

Trie树就是字符树,其核心思想就是空间换时间。
举个简单的例子。
给你100000个长度不超过10的单词。对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。
这题当然可以用hash来,但是我要介绍的是trie树。在某些方面它的用途更大。比如说对于某一个单词,我要询问它的前缀是否出现过。这样hash就不好搞了,而用trie还是很简单。
现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否有它。那么这个算法的复杂度就是O(n^2)。显然对于100000的范围难以接受。现在我们换个思路想。假设我要查询的单词是abcd,那么在他前面的单词中,以b,c,d,f之类开头的我显然不必考虑。而只要找以a开头的中是否存在abcd就可以了。同样的,在以a开头中的单词中,我们只要考虑以b作为第二个字母的……这样一个树的模型就渐渐清晰了……
假设有b,abc,abd,bcd,abcd,efg,hii这6个单词,我们构建的树就是这样的。

对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。
那么,对于一个单词,我只要顺着他从跟走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。把这个节点标记为红色,就相当于插入了这个单词。
这样一来我们询问和插入可以一起完成,所用时间仅仅为单词长度,在这一个样例,便是10。
我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。

密码破译
【问题描述】
由于最近功课过于繁忙,Tim竟然忘记了自己电脑的密码,幸运的是Tim在设计电脑密码的时候,用了一个非常特殊的方法记录下了密码。这个方法是:Tim把密码和其它的一些假密码共同记录在了一个本子上面。为了能够从这些字符串中找出正确的密码,Tim又在另外一个本子上面写了一个很长的字符串,而正确的密码就是在这个字符串中出现次数最多的一个密码。例如串ababa,假若密码是abab和aba,那么正确的密码是aba,因为aba在这个字符串中出现了2次。
现在你得到了Tim的这两个本子,希望你能够编写一个程序帮助Tim找出正确的密码。
【输入】
输入由两个部分组成。其中第一部分由若干行组成,每一行记录了一个密码,密码的均长度小于等于255位,并且都由小写字母组成。然后一个空行,第二部分记录了一个很长的字符串,并且以’.’结束,其中只包含了小写字母。
【输出】
输出文件名为Pass.out。输出文件由仅有一行,为一个整数,表示正确密码在字符串中出现的次数。如果这个出现次数为0,输出“No find”。
【样例】:
Pass.in                                        Pass.out
ab                                            6
abc
bdc
abcd
abcabcabcdbdabcbabdbcabdbdbdbd.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值