trie树略解

trie树也叫字典树,前缀树
字典树(Trie)有如下几条性质

  1. 结点不存值,依靠树枝(边)存值
  2. 从根节点到某一处标记点为一个单词
  3. 每个结点到其子节点的边上的值各不相同
  4. 插入和查询复杂度均为O(mn),m为字符串个数,n为字符串平均长度
  5. 树深度由最长字符串决定

依次便可做出trie树的结点结构

struct trie{
	int cnt=0;
	bool word=0;
	trie * son[26]={0};
};

让我们依次价绍这几个成员的含义

  1. cnt 这条边上有几个单词经过,即有多少指定的前缀相同的单词
  2. word 从根节点这个结点是否是一个单词
  3. son[26] 其子节点的地址;

依据其基本性质和结构体成员,写出构造函数如下

void make()
{
 string s;
 cin>>s;
 int lo=s.lenth();
 trie * now=root;
 for(int i=0;i<lo;i++){
   if(now->son[s[i]-'a']) now = now->son[s[i]-'a'];
   else {
     now->son[s[i]-'a']=new trie;
     now=now->son[s[i]-'a'];
   }
   now->cnt++;
 }
 now->word=1;
}

首先读入一个字符串,得到其长度,并将查询指针调至根节点
这时从字符串第一个字符开始查询该字符是否已经存过
如果存过则将查询指针所在结点的cnt++,并移至该节点,如果未存过,则申请一个新结点连接到相应位置上
直到最后一个结点,将最后一个结点中的word标记改为1

根据trie树性质同时可写出查询函数

void check()
{
	char s[55];
	scanf("%s",s);
	int lo=strlen(s),i;
	trie * now=root;
	for(i=0;i<lo;i++){
		if(now->son[s[i]-'a']){
			now = now->son[s[i]-'a'];
			continue;
		}
		else {
			printf("NO\n");
			break;
		}
	}
	if(i == lo){
		printf("YES\n");
	}
}

首先读入需要查询的字符串,按生成树的方式判断是否存过某字符,若存过,则进入所存结点
若未存过,则break,防止访问空指针,若只判断是否含有某前缀,则上述函数可完成,查询单词时,可将最后一处判断改为

if(i == lo && now->word){
	printf("YES\n");
}
else{
	printf("NO\n");
}

即当循环结束,字符串在树中时,判断是否这个字符串是整个单词

当树生成时,自动实现字符串的排序
可用递归实现
同时可用递归实现树的删除

与hash比较

Trie 的强大之处就在于它的时间复杂度。O(n),与 Trie 中保存了多少个元素无关。
Hash 表号称是 O(1) 的,但在计算 hash 的时候就肯定会是 O(n) ,而且还有可能冲突的问题
Trie 的缺点是空间消耗很高。

trie树拓展

AC自动机

为trie树上的KMP,留于KMP处详解

后缀树

可实现后缀自动机

基数数

将二进制数拆成几个2位数或几个4位数,按trie树方式存入
好像没什么卵用

trie树例题:

洛谷 2580
题解

#include<cstdio>
#include<cstring>
using namespace std;
struct trie{
	bool check=0;
	bool word=0;
	trie * son[26]={0};
};
trie *root;
void make()
{
	char s[55];
	scanf("%s",s);
	int lo=strlen(s);
	trie * now=root;
	for(int i=0;i<lo;i++){
		if(now->son[s[i]-'a']){
			now = now->son[s[i]-'a'];
			continue;
		}
		else {
			now->son[s[i]-'a']=new trie;
			now=now->son[s[i]-'a'];
		}
	}
	now->word=1;
}

void check()
{
	char s[55];
	scanf("%s",s);
	int lo=strlen(s),i;
	trie * now=root;
	for(i=0;i<lo;i++){
		if(now->son[s[i]-'a']){
			now = now->son[s[i]-'a'];
			continue;
		}
		else {
			printf("WRONG\n");
			break;
		}
	}
	if(i == lo && now->word){
		if(now->check){
			printf("REPEAT\n");
		}
		else{
			printf("OK\n");
			now->check=1;
		}
	}
}

int main()
{
	root = new trie;
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		make();
	}
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		check();
	}
	return 0;
}

codevs 4189
题解:

#include<cstdio>
#include<cstring>
using namespace std;
struct trie{
	trie * son[26];
};
trie *root;
void make()
{
	char s[55];
	scanf("%s",s);
	int lo=strlen(s);
	trie * now=root;
	for(int i=0;i<lo;i++){
		if(now->son[s[i]-'a']){
			now = now->son[s[i]-'a'];
			continue;
		}
		else {
			now->son[s[i]-'a']=new trie;
			now=now->son[s[i]-'a'];
		}
	}
}

void check()
{
	char s[55];
	scanf("%s",s);
	int lo=strlen(s),i;
	trie * now=root;
	for(i=0;i<lo;i++){
		if(now->son[s[i]-'a']){
			now = now->son[s[i]-'a'];
			continue;
		}
		else {
			printf("NO\n");
			break;
		}
	}
	if(i == lo){
		printf("YES\n");
	}
}

int main()
{
	root = new trie;
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		make();
	}
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		check();
	}
	return 0;
}

hihocoder 1014

#include<cstdio>
#include<cstring>
using namespace std;
struct trie{
	int cnt=0;
	trie * son[26]={0};
};
trie a;
trie *root=&a;
void make()
{
	char s[15];
	scanf("%s",s);
	int lo=strlen(s);
	trie * now=root;
	for(int i=0;i<lo;i++){
		if(now->son[s[i]-'a']){
			now = now->son[s[i]-'a'];
			now->cnt++;
			continue;
		}
		else {
			now->son[s[i]-'a']=new trie;
			now=now->son[s[i]-'a'];
			now->cnt++;
		}
	}
}
void check()
{
	char s[55];
	scanf("%s",s);
	int lo=strlen(s),i;
	trie * now=root;
	for(i=0;i<lo;i++){
		if(now->son[s[i]-'a']){
			now = now->son[s[i]-'a'];
			continue;
		}
		else {
			printf("0\n");
			break;
		}
	}
	if(i == lo){
		printf("%d\n",now->cnt);
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		make();
	}
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		check();
	}
	return 0;
}
posted @ 2018-08-13 19:51  smallshulker  阅读(146)  评论(0编辑  收藏  举报