字典树 trie

具体原理:刘汝佳《算法竞赛入门经典训练指南》P208

作用:字典树又叫单词查找树(Trie)或前缀树,是一个实现字符串。你可以在O(m)(m为所给单词的长度)时间内判断出该单词是否属于字典

代码模板:
 

 
#include<cstdio>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<list>
#include<set>
#include<map>
using namespace std;
#define N 300000+5
#define MAX 26
 
typedef long long ll;
 
const int maxnode=400000+100;//预计字典树最大节点数目
const int sigma_size=26;       //每个节点的最多儿子数
struct Trie
{
    int ch[maxnode][sigma_size];//ch[i][j]==k表示第i个节点的第j个儿子是节点k
    int val[maxnode];//val[i]==x表示第i个节点的权值为x
    int sum[maxnode];//sum[i]==x表示第i个节点的次数为x,便于删除
    int sz;//字典树一共有sz个节点,从0到sz-1标号
 
    //初始化
    void clear()
    {
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));//ch值为0表示没有儿子
        memset(sum,0,sizeof(sum));
    }
 
    //在字典树中插入单词s,但是如果已经存在s单词会重复插入且覆盖权值
    //所以insert前需要判断一下是否已经存在s单词了
    void insert(string s)
    { 
		int u=0,n=s.length();
        for(int i=0;i<n;i++)///建立字典树
        {
            int id=s[i]-'a';
            if(ch[u][id]==0)//无该儿子
            {
                ch[u][id]=sz;
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz++]=0;
            }
            u=ch[u][id];
            sum[u]++;
        }
        val[u]=n;
    }
 
    //在字典树中查找单词s
    bool find1(string s)
    {
        int n=s.length(),u=0;
        for(int i=0;i<n;i++)
        {
            int id=s[i]-'a';
            if(ch[u][id]==0)
                return false;
            u=ch[u][id];
     
        }
        return val[u];
    }
    int find2(string s)///查找前缀为s的个数
    {
    	int n=s.length(),u=0;
        for(int i=0;i<n;i++)
        {
            int id=s[i]-'a';
            if(ch[u][id]==0)
                return 0;
            u=ch[u][id];
     
        }
        return sum[u];
    }
    void del(string s,int cnt) //删除前缀s的所有单词
    {
	int n=s.length(),u=0;
	for(int i=0;i<n;i++)
	{
		int id=s[i]-'a';
	    if(ch[u][id]==0)
			return ;
		u=ch[u][id];
		sum[u]-=cnt;
	}
	
	for(int i=0;i<26;i++)
		ch[u][i]=0;
    }
};
Trie trie;
 
int main()
{
	int n;
	while(scanf("%d",&n)!=-1)
	{
		trie.clear();
		for(int i=1;i<=n;i++)
		{
			string s1,s2;
			cin>>s1>>s2;
			if(s1[0]=='i')
			{
				trie.insert(s2);
			}
			else if(s1[0]=='d')
			{
				trie.del(s2,trie.find2(s2));
			}
			else
			{
			    if(trie.find2(s2)!=0)
				{
					printf("Yes\n");
				}
				else
					printf("No\n");
			}
		}
		
	}
    return 0;
}

动态申请

#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int MAXN = 1e2 + 50;
const int MAXM = 1e5 + 50;
const int MOD = 1e9 + 7;

struct node
{
    int v;
    node* nxt[26];
    node()
    {
        v = 0;
        memset(nxt, NULL, sizeof(nxt));
    }
};

void trie_insert(node* root, char* word)
{
    node* now = root;
    int len = strlen(word);
    for (int i = 0; i < len; i++)
    {
        int id = word[i] - 'a';
        if (now->nxt[id] == NULL)
            now->nxt[id] = new node();
        now = now->nxt[id];
        now->v++;
    }
}

void trie_delete(node* root, char* word)
{
    node* now = root;
    int len = strlen(word), del;
    for (int i = 0; i < len; i++)
    {
        int id = word[i] - 'a';
        if (now->nxt[id] == NULL)
            return;
        now = now->nxt[id];
        del = now->v;
    }
    now = root;
    for (int i = 0; i < len; i++)
    {
        int id = word[i] - 'a';
        if (now->nxt[id] == NULL)
            return;
        if (i == len - 1)
        {
            free(now->nxt[id]);
            now->nxt[id] = NULL;
            return;
        }
        now = now->nxt[id];
        now->v -= del;
    }
}

bool trie_query(node* root, char* word)
{
    node* now = root;
    int len = strlen(word);
    int ans = INF;
    for (int i = 0; i < len; i++)
    {
        int id = word[i] - 'a';
        if (now->nxt[id] == NULL)
            return false;
        now = now->nxt[id];
    }
    return now->v != 0;
}

int main()
{
    int n;
    scanf("%d", &n);
    char op[35], word[35];
    node* root = new node();
    while (n--)
    {
        scanf("%s%s", op, word);
        if (strcmp(op, "insert") == 0)
            trie_insert(root, word);
        else if (strcmp(op, "delete") == 0)
            trie_delete(root, word);
        else
            printf("%s\n", trie_query(root, word) ? "Yes" : "No");
    }
    return 0;
}

01字典树

数组:

#include<cstdio>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<numeric>
#include<cctype>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<list>
#include<set>
#include<map>
using namespace std;
#define N 10000+5

typedef long long ll;
 
const int maxnode=1500000+100;//预计字典树最大节点数目
const int sigma_size=35;       //每个节点的最多儿子数
struct Trie
{
    int ch[maxnode][sigma_size];//ch[i][j]==k表示第i个节点的第j个儿子是节点k
    int val[maxnode];//val[i]==x表示第i个节点的权值为x
    int sum[maxnode];//sum[i]==x表示第i个节点的次数为x,便于删除
    int sz;//字典树一共有sz个节点,从0到sz-1标号
 
    //初始化
    void clear()
    {
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));//ch值为0表示没有儿子
        memset(sum,0,sizeof(sum));
    }
 
    //在字典树中插入单词s,但是如果已经存在s单词会重复插入且覆盖权值
    //所以insert前需要判断一下是否已经存在s单词了
    void insert(int num)
    { 
		int u=0;
        for(int i=31;i>=0;i--)///建立字典树
        {
            int id=((num>>i)&1);
            if(ch[u][id]==0)//无该儿子
            {
                ch[u][id]=sz;
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz++]=0;
            }
            u=ch[u][id];
            sum[u]++;
        }
        //val[u]=n;
    }
    int find3(int num1,int num2)
    {
    	int u=0;
    	int ans=0;
    	for(int i=31;i>=0;i--)
		{
			int t1=((num1>>i)&1);
			int t2=((num2>>i)&1);
			
			if(t1)
			{
				if(t2)
				{
					if(ch[u][1])
					ans+=sum[ch[u][1]];
					u=ch[u][0] ;
				}	
				else
				{
					u=ch[u][1];
				}
			}
			else
			{
				if(t2)
				{
					if(ch[u][0])
						ans+=sum[ch[u][0]];
					u=ch[u][1];
				}
				else
					u=ch[u][0];
			}
			if(u==0) break;
		}
		return ans;
    }
    void del(int num,int cnt) 
    {
		int u=0;
	    for(int i=31;i>=0;i--)
	    {
		   int id=((num>>i)&1);
		   if(ch[u][id]==0)
			      return ;
		   u=ch[u][id];
		   sum[u]-=cnt;
	    }
    }
};
Trie trie;
int main()
{
	int n;
	scanf("%d",&n);	  
	trie.clear();
    for(int i=1;i<=n;i++)
	{
		int op;
		scanf("%d",&op);
		if(op==1)
		{
			int x;
			scanf("%d",&x);
			trie.insert(x);
		}
		else if(op==2)
		{
			int x;
			scanf("%d",&x);
			trie.del(x,1);
		}
		else
		{
			int x,y;
			scanf("%d%d",&x,&y);
			printf("%d\n",trie.find3(x,y));
		}
	}
    return 0;
}

动态开点

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#define rt return
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define db(x) cout<<"== [ "<<x<<" ] =="<<endl;
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
inline void getInt(int* p);
const int maxn=1000010;
const int inf=0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/

struct node
{
    int num;
    node *Next[2];
    node()
    {
        num=0;
        Next[0]=Next[1]=nullptr;
    }
};

void Add(node *head , int num)
{
    node *p=head;
    for(int i=31;i>=0;i--)
    {
        int k=((num>>i)&1);
        if(p->Next[k]== nullptr)
        {
            node *q =new node();
            p->Next[k]= q;
        }
        p = p->Next[k];
        p->num++;
    }
//    p->num=num;
}
void Del(node *head ,int num)
{
    node *p=head;
    for(int i=31;i>=0;i--)
    {
        int k=((num>>i)&1);
        if(p->Next[k]==NULL)
        {
            node * q=new node();
            p->Next[k] = q;
        }
        p = p->Next[k];
        p->num--;
    }

}
int Find(node *head, int num)
{
    node *p = head;
    for(int i=31;i>=0;i--)
    {
        int k=((num>>i)&1);
        if(p->Next[k^1]!=NULL)
        {
             p = p->Next[k^1];

        }else
        {
            p = p->Next[k];
        }
    }
    return p->num;
}
void query(node * root,int x,int y)
{
    node *p = root;
    int res=0;
    for(int i=31;i>=0;--i)
    {
        int tx=(x&(1<<i));
        int tl=(y&(1<<i));
        if(tx)
        {
            if(tl)
            {
                if(p->Next[1])
                    res+=p->Next[1]->num;
                p=p->Next[0];
            }else
            {
                p=p->Next[1];
            }
        }else
        {
            if(tl)
            {
                if(p->Next[0])
                    res+=p->Next[0]->num;
                p=p->Next[1];
            }else
            {

                p=p->Next[0];
            }
        }
        if(p==nullptr)
            break;//
    }
    printf("%d\n",res);
}
int n;
int main()
{
    gg(n);
    node *head = new node();
    repd(i,1,n)
    {
        int op,x,y;
        gg(op);
        if(op==1)
        {
            gg(x);
            Add(head,x);
        }else if(op==2)
        {
            gg(x);
            Del(head,x);
        }else
        {
            gg(x),gg(y);
            query(head,x,y);
        }
    }
    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}

 

经典例题: 

 

HDU 1251 统计难题                    字典树简单应用(找出所有以字符串s为前缀的单词个数)

Uva1401 Remember the Word    字典树简单应用(求一个字符串能有多少种方式通过字典中的单词构成)

HDU 1671 Phone List                   字典树 (多种做法:问你字典中是否有一个字符串是其他字符串的前缀)

HDU 1247 Hat’s Words(              字典树Trie):单词匹配

异或(两题一样,推荐第二道)

CH 1602 The XOR Largest Pair 字典树+异或

NBUT-1597  Find MaxXorSum     经典字典树求异或最大值(数据量大)

HDU – 5536 Chip Factory           字典树的删除

CodeForces – 633C Spy Syndrome 2   ( 字典树+dfs)

POJ 3764 The xor-longest Path    dfs+字典树求最大异或

    原文作者:Trie树
    原文地址: https://blog.csdn.net/sdz20172133/article/details/84202331
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞