數據結構——字典樹

高大上,實用,真香;

字典樹,顧名思義:用來當成字典用的 樹型結構處理方式——(兩種應用: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;
}

這是這是這是字典樹,超好用,簡單易懂;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章