字典树详解

字典树是一种用于统计和排序大量的字符串的数据结构。它的原理是把具有相同前缀的字符建立一颗树。

例如,我们有字符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;
}