程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 字典樹(Trie)

字典樹(Trie)

編輯:C++入門知識

學習字典樹一段時間 了,個人覺得字典樹比較容易掌握,但是ACM中題目變化多端,我們只有多練習,才能對字典樹的應用有更深的把握。

下面講解一下字典樹。

其實掌握字典樹,只需要寫過一個關於字典樹的程序,記住它的結構就可以了。先看看字典樹的定義


[cpp]
struct Trie 

     Trie *next[MAX]; 
     bool isword; 
}; 

struct Trie
{
     Trie *next[MAX];
     bool isword;
};


其實上面那個字典樹結點的定義只是來自我做的一個題目,裡面的元素視你做的題目而定,不過 Trie *next[] 這個數組就是一定的了,只不過他的大小也視你的題目而定。(可能是26個小寫字母,也可能是52個大小寫字母或者其他)

相信一個例子大家就都掌握了,建議一定先看看題目(自己敲完這一個題目之後,一定可以A掉其他許多關於字典樹的題目了)
 


題目的大概意思就是說給定一些單詞,要你從中找到某些單詞,而這個單詞是由另外兩個單詞組成的。

其實我們就是利用字符的ascii碼來給他對應的索引

這個題目就是把每個單詞拆成兩部分,看看是不是每一部分在字典樹中都是一個單詞


先來看看建樹的過程。(耐心一點,一步一步看懂程序,just one time)


必要的時候動手畫一畫圖


[cpp]
<SPAN style="FONT-SIZE: 18px">void createTrie(char str[])//傳進來輸入的字符串  

    int len = strlen(str); 
    Trie *p = root,*q = NULL; 
    for(int i=0;i<len;i++) 
    { 
         int id = str[i]-'a'; 
         if(p->next[id]==NULL) 
         { 
              q = new Trie; 
              for(int j=0;j<MAX;j++) 
               q->next[j] = NULL; 
               q->isword = false; 
              p->next[id] = q; 
         } 
          if(i==len-1) 
          p->next[id]->isword = true; 
          p = p->next[id]; 
    } 
 
}</SPAN> 

void createTrie(char str[])//傳進來輸入的字符串
{
    int len = strlen(str);
    Trie *p = root,*q = NULL;
    for(int i=0;i<len;i++)
    {
         int id = str[i]-'a';
         if(p->next[id]==NULL)
         {
              q = new Trie;
              for(int j=0;j<MAX;j++)
               q->next[j] = NULL;
               q->isword = false;
              p->next[id] = q;
         }
          if(i==len-1)
          p->next[id]->isword = true;
          p = p->next[id];
    }

}再看看查找的過程


[cpp] 
<SPAN style="FONT-SIZE: 18px">bool findTrie(char str[]) 

     int len = strlen(str); 
     Trie *p = root; 
   for(int i=0;i<len;i++) 
   { 
        int id = str[i]-'a'; 
        if(p->next[id]==NULL) 
        { 
              return false; 
        } 
         p = p->next[id]; 
   } 
   if(p->isword) 
   return true; 
   else 
     return false; 
}</SPAN> 

bool findTrie(char str[])
{
     int len = strlen(str);
     Trie *p = root;
   for(int i=0;i<len;i++)
   {
        int id = str[i]-'a';
        if(p->next[id]==NULL)
        {
              return false;
        }
         p = p->next[id];
   }
   if(p->isword)
   return true;
   else
     return false;
}
最後記得釋放掉這顆字典樹


[cpp] 
<SPAN style="FONT-SIZE: 18px">void del(Trie *root) 

   for(int i=0;i<26;i++) 
   { 
        if(root->next[i]!=NULL) 
        { 
             del(root->next[i]); 
        } 
   } 
   delete root; 
}</SPAN> 

void del(Trie *root)
{
   for(int i=0;i<26;i++)
   {
        if(root->next[i]!=NULL)
        {
             del(root->next[i]);
        }
   }
   delete root;
}注意在建立樹的時候,先產生一個根節點 Trie *root = new Trie; //我幾乎每次都忘了先new出來一個

下面貼一下完整代碼


[cpp] 
<SPAN style="FONT-SIZE: 18px">#include <iostream> 
#include <cstring>  
#include <cstdio>  
using namespace std; 
const int MAX = 26; 
struct Trie 

     Trie *next[MAX]; 
     bool isword; 
}; 
Trie *root = new Trie; 
char word[50000][30]; 
void createTrie(char str[]) 

    int len = strlen(str); 
    Trie *p = root,*q = NULL; 
    for(int i=0;i<len;i++) 
    { 
         int id = str[i]-'a'; 
         if(p->next[id]==NULL) 
         { 
              q = new Trie; 
              for(int j=0;j<MAX;j++) 
               q->next[j] = NULL; 
               q->isword = false; 
              p->next[id] = q; 
         } 
          if(i==len-1) 
          p->next[id]->isword = true; 
          p = p->next[id]; 
    } 
 

bool findTrie(char str[]) 

     int len = strlen(str); 
     Trie *p = root; 
   for(int i=0;i<len;i++) 
   { 
        int id = str[i]-'a'; 
        if(p->next[id]==NULL) 
        { 
              return false; 
        } 
         p = p->next[id]; 
   } 
   if(p->isword) 
   return true; 
   else 
     return false; 

void del(Trie *root) 

   for(int i=0;i<MAX;i++) 
   { 
        if(root->next[i]!=NULL) 
        { 
             del(root->next[i]); 
        } 
   } 
   delete root; 

int main() 

    int num=0; 
    char str1[30],str2[30]; 
    for(int i=0;i<MAX;i++) 
    { 
         root->next[i] = NULL; 
    } 
    root->isword = false; 
    while(gets(word[num])) 
    { 
         createTrie(word[num]); 
         num++; 
    } 
    for(int i=0;i<num;i++) 
    { 
         int len = strlen(word[i]); 
         if(len==1) 
          continue; 
        for(int j=0;j<len;j++)//從每個單詞的各部分拆開  
     { 
          int k; 
          if(j==len-1) continue; 
         for(k=0;k<=j;k++) 
          { 
               str1[k] = word[i][k]; 
          } 
          str1[k]='\0'; 
          int k2=0; 
          for(int l=k;l<len;l++) 
          { 
               str2[k2++]=word[i][l]; 
          } 
          str2[k2]='\0'; 
          if(findTrie(str1)&&findTrie(str2)) 
          { 
               cout<<word[i]<<endl; 
               break;//居然錯在這裡了(可能會重復輸出)  
          } 
     } 
    } 
     del(root); 
    return 0; 

</SPAN> 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved