字典樹詳解
字典樹是一種用於統計和排序大量的字符串的數據結構。它的原理是把具有相同前綴的字符建立一顆樹。
例如,我們有字符acdr,aced,bde,asd,ceed,asdr,frt進行建樹的話應該是這樣:
字典樹兩個基本操作是:1.建樹2.查詢
1.建樹
建樹的方式兩種一種是用數組建樹,一種是鏈表建樹。在acm和oi中常用的建樹方式是數組建樹,在這裏我們主要講解一下數組建樹。二者建樹的思想是一致的
假定給你n個字符,將每個字符插入樹中其實就算完成了建樹的過程。我們用二維數組tire來作爲樹的儲存結構。
tire[rt][c] = index代表rt節點與index相連,且index節點代表以c字符爲結尾的一個字符串。 假定將str字符串插入字典樹中,那麼檢測當前節點rt是否與str[i]相連,如果相連的話tire[rt][str[i]] > 0,如果不相連的話tire[rt][str[i]] == 0,這時候我們應該創建一個新的節點使得rt與str[i]相連。代碼如下:
void insert(char* data)
{
int len = strlen(data);
rt = root;
for(int i = 0; i < len; i++) //建樹的過程
{
int y = data[i] - 'a';
if(tire[rt][y] == 0) //如果rt與data[i]不相連,就創建一個新的節點使兩者相連
{
tire[rt][y] = ++index;
}
rt = tire[rt][y];
}
}
2.查詢
查詢過程因題目而異。
如Hdu_1251,這個題要在建樹的過程中把每一個前綴的數量統計下來
代碼如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define ll long long
#define mmset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N = 1e6;
int trie[N][30], num[N] = {0};
int root = 0, index = 1;
void insert(char* data)
{
int len = strlen(data);
int rt = root;
for(int i = 0; i < len; i++)
{
int y = data[i] - 'a';
if(trie[rt][y] == 0)
{
trie[rt][y] = index++;
}
rt = trie[rt][y];
num[rt]++;
}
}
int query(char* str)
{
int len = strlen(str);
int rt = root;
for(int i = 0; i < len; i++)
{
int y = str[i] - 'a';
rt = trie[rt][y];
if(rt == 0)
{
return 0;
}
}
return num[rt];
}
int main()
{
char word[11];
while(gets(word))
{
if(word[0]==NULL) //空行。gets讀入的回車符會自動轉換爲NULL。
break;
insert(word);
}
while(gets(word))
printf("%d\n",query(word));
return 0;
}