Trie樹可以被用來統計公共前綴,例如模板題的HDU統計難題。
以及模板題的一個變型題
POJ Shortest Prefixes
這道變型題用來找出每個單詞最短的前綴縮寫,也就是隻要找出從第一個字母一直到最後一個字母哪一個前綴組合在所給樣例中只存在一次。裏附上一個利用Trie樹比網上例程更簡單的做法,也就是在建立完Trie樹,到達每個結點後,先直接輸出,再判斷這個結點被幾個單詞所共享。如果只有一個,就可以直接return,再判斷下一個單詞;如果這個單詞走到了頭也沒有出現特有的一個字母位也沒有關係,因爲已經把整個單詞輸出完了,而其他更長的單詞也會因爲前面的字母結點都已經共享,而輸出相應更長的前綴。
附AC代碼:(抓狂,WA了四次的原因居然是字符串開的不夠大,比對了網上的AC代碼發現要開到1000*25纔可以)
#include<iostream>
using namespace std;
#include<stdio.h>
#include<string.h>
struct node
{
node* br[26];
int sum ;
node()
{
sum =0;
memset(br,0,sizeof(br));
}
} ;
node *head;
char list[1001][25];
void insert(char *m)
{
int l = strlen(m);
node *t = head;
node *s;
for(int i = 0; i < l;i++)
{
int x= m[i]-'a';
if(t->br[x]==NULL)
{
s = new node;
s->sum = 1;
t->br[x]= s;
}
else
{
t->br[x]->sum++;
}
t = t->br[x];
}
}
void find(char * m)
{
int l = strlen(m);
node *h= head;
for(int i = 0 ;i< l;i++)
{
int x= m[i]-'a';
if(h->sum!=1)
cout<<m[i];
else {
return;
}
h = h->br[x];
}
}
int main()
{
head = new node;
int i,t=0;
while(~scanf("%s",list[t]))
insert(list[t++]);
for(i=0;i<t;i++)
{
if(i)cout<<endl;
cout<<list[i]<<' ';
find(list[i]);
}
return 0;
}
其次就是Trie樹最核心的用法了,那就是作爲字典存儲相應信息。作爲字典存儲時,每個結點的數據域應該改變,例如可以刪去當前結點共用的單詞數,增添一個變量判斷從頭節點到當前結點能否構成一個完整的單詞,而當可以的時候,還要記錄下另一個單詞,因此每個結點還應附加一個字符串數組用來儲存。
HDU What Are You Talking About
本題給出了英語和火星語的對照,再給出若干句火星文,需要我們翻譯成英文,這道題其實很簡單,但是在輸入操作的時候有一些小技巧,阻擋了AC的步伐
附AC代碼如下:
#include<iostream>
#include<cstring>
using namespace std;
typedef struct Trie_node
{
int count; // 統計單詞前綴出現的次數
struct Trie_node* next[26]; // 指向各個子樹的指針
bool exist; // 標記該結點處是否構成單詞
char trans[11]; // 翻譯
}TrieNode , *Trie;
TrieNode* createTrieNode()
{
TrieNode* node = (TrieNode *)malloc(sizeof(TrieNode));
node->count = 0;
node->exist = false;
memset(node->next , 0 , sizeof(node->next)); // 初始化爲空指針
return node;
}
void Trie_insert(Trie root, char* word , char* trans)
{
Trie node = root;
char *p = word;
int id;
while( *p )
{
id = *p - 'a';
if(node->next[id] == NULL)
{
node->next[id] = createTrieNode();
}
node = node->next[id]; // 每插入一步,相當於有一個新串經過,指針向下移動
++p;
node->count += 1; // 這行代碼用於統計每個單詞前綴出現的次數(也包括統計每個單詞出現的次數)
}
node->exist = true; // 單詞結束的地方標記此處可以構成一個單詞
strcpy(node->trans , trans);
}
char* Trie_search(Trie root, char* word)
{
Trie node = root;
char *p = word;
int id;
while( *p )
{
id = *p - 'a';
node = node->next[id];
++p;
if(node == NULL)
return 0;
}
if(node->exist) // 查找成功
return node->trans;
else // 查找失敗
return NULL;
}
int main(void)
{
Trie root = createTrieNode(); // 初始化字典樹的根節點
char str1[3003] , str2[3003] , str[3003] , *p;
int i , k;
scanf("%s",str1);
while(scanf("%s",str1) && strcmp(str1 , "END") != 0)
{
scanf("%s",str2);
Trie_insert(root , str2 , str1);
}
getchar();
gets(str1);
k = 0;
while(gets(str1))
{
if(strcmp(str1 , "END") == 0)
break;
for(i = 0 ; str1[i] != '\0' ; ++i)
{
if(str1[i] >= 'a' && str1[i] <= 'z')
{
str[k++] = str1[i];
}
else
{
str[k] = '\0';
p = Trie_search(root , str);
if(p)
printf("%s", p);
else
printf("%s",`
str);
k = 0;
printf("%c", str1[i]);
}
}
printf("\n");
}
return 0;
}
最後來道題練下手吧(05/24)
Babefish
附AC代碼
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
struct node{
node*br[26];
char x;
bool exist;
char trans[12];
node()
{
for(int i = 0;i<26;i++)
br[i]=NULL;
}
};
node*head;
void insert(char *text,char *trans)
{
int l = strlen(text);
node *h=head,*s;
for(int i = 0; i < l; i ++)
{
int x = text[i]-'a';
if(h->br[x]==NULL)
{
s = new node();
h->br[x] = s;
h->exist= true;
}
h=h->br[x];
}
strcpy(h->trans,trans);
}
void find(char *text)
{
int l = strlen(text);
node *h = head;
int valid = 1;
for(int i = 0; i< l;i++)
{
int x = text[i]-'a';
h = h->br[x];
if(h ==NULL)
{
valid = 0;
break;
}
}
if(valid&&h->exist)
valid = 1;
else
valid = 0;
if(valid )
printf("%s\n",h->trans);
else
printf("eh\n");
}
int main()
{
head = new node;
char str1[15], str2[15], str[30];
int i,j;
while(gets(str))
{
if(strlen(str) == 0)
break;
i = 0; j = 0;
while(str[i] != ' ')
str1[j++] = str[i++];
str1[j] = '\0'; i++;
j = 0;
while(str[i] != '\0')
str2[j++] = str[i++];
str2[j] = '\0';
insert(str2, str1);
}
while(~scanf("%s",str))
find(str);
return 0;
}