高大上,實用,真香;
字典樹,顧名思義:用來當成字典用的 樹型結構處理方式——(兩種應用:1.字母數,2. 01字典樹)
幾個模塊:1.建樹。2.查詢樹。3.刪除一些元素。
上圖
這是一棵存儲單詞的字典樹,數組tree[N][26], 表示字典樹,圖中的數字就是開闢空間的大小,從上至下每當沒有相同字母時就開闢新的空間(代碼中見詳解),增加分支;
這兒需要注意的是:要靈活使用輔助數組進行,標記或者存儲數據。輸出查找數據、刪除元素都是靠這
代碼詳解:
就N組單詞,m次詢問,若詢問的單詞在N組單詞中輸出Yes並刪除,沒有則輸出No;
#include<stdio.h> //是時候鍛鍊自己閱讀代碼的能力了;
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#include<vector>
using namespace std;
const int N=1e6;
int tree[N][26]; // 在開內存時要注意,儘量開大點防止RE;
int p[N],tot=1; // tot標記,記錄內存開的大小;
bool q[N]; // 這應該認識吧!
void build_tree(char str[]) // 建樹;
{
int root=0,i,len,pos;
len=strlen(str);
for(i=0;i<len;i++){
pos=str[i]-'a';
if(!tree[root][pos]){
tree[root][pos]=tot++;
}
root=tree[root][pos]; //理解這一步就懂了,root是字典樹的指引,相當於是個指針,標號;
p[root]++; //標記字母出現的次數,方便後面的刪除操作;其他情況也可以用;
}
q[root]=true; //標記再這一點是否有這個單詞;
}
bool search_tree(char str[])
{
int root=0,i,len,pos;
len=strlen(str);
for(i=0;i<len;i++){
pos=str[i]-'a';
if(!tree[root][pos]||p[tree[root][pos]]<=0) //這兒p[]數組下標是指下一節點的字母剩餘次數;
return false;
root=tree[root][pos]; //和上面一樣;
}
if(!q[root])
return false;
return true;
}
void delet(char str[])
{
int root=0,i,len,pos;
len=strlen(str);
for(i=0;i<len;i++){
pos=str[i]-'a';
root=tree[root][pos]; //和上面一樣;
p[root]--; //減去一次出現的次數;
}
}
int main()
{
int n,m,i;
char str[20];
memset(tree,0,sizeof(tree));
memset(p,0,sizeof(p));
memset(q,false,sizeof(q)); //用這個時注意頭文件<cstring>;
scanf("%d%d",&n,&m);
getchar();
for(i=0;i<n;i++){
scanf("%s",str);
build_tree(str);
}
for(i=0;i<m;i++){
scanf("%s",str);
if(search_tree(str)){
printf("Yes\n");
delet(str);
}
else
printf("No\n");
}
return 0;
}
下面是01字典樹,原理相似只是將數字轉換成二進制儲存在數組中;一般用於尋找最大異或數;
貼道題吧;
模版題:
N個數,m次詢問,每次詢問要求找出與x異或最大的數;
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
const int N=1e5+55;
long long p[N];
int tree[N][2];
int tot=1;
void build_tree(long long x)
{
int root=0,i,pos;
for(i=30;i>=0;i--){ //從最高位開始,因爲最高位大小決定了異或數的大小,高位優先級最高;
pos=(x>>i)&1; // 取最高位;
if(!tree[root][pos]){
tree[root][pos]=tot++; // 開闢新的單元;
}
root=tree[root][pos];
}
p[root]=x; // 標記數字;
}
long long search_tree(long long x)
{
int root=0,i,pos;
for(i=30;i>=0;i--){
pos=(x>>i)&1;
if(tree[root][pos^1]) // 找異或最大的數字,不信自己手動模擬;
root=tree[root][pos^1];
else
root=tree[root][pos]; // 沒有滿足條件的就只能選另一個較小的了;
}
return p[root];
}
int main()
{
int n,i,m;
long long x;
memset(tree,0,sizeof(tree));
memset(p,0,sizeof(p));
scanf("%d%d",&n,&m);
for(i=0;i<n;i++){
scanf("%lld",&x);
build_tree(x);
}
for(i=0;i<m;i++){
scanf("%lld",&x);
printf("%lld\n",search_tree(x)); // 01字典樹也存在刪除元素哦;
}
return 0;
}
這是這是這是字典樹,超好用,簡單易懂;