字典树总结
在实际生活中,图书馆、书店都会遇到一种麻烦,就是不知道如何储存所有的书名,因为藏书实在是太多了。这种情形非常常见。
由此单词查找树便出现了:Trie树,是一种树形结构,是一种哈希树的变种,它通过储存大部分字符串的前缀来达到不仅是存储空间而且是查找效率的优化。
字典树的操作大致分为三种:插入字符串、查找字符串、删除字符串。
首先我们要构造一棵树。根节点编号设置为1。这个结点没有实际意义,只作为查找的起点。
注意:虽然有些结点存在,但有可能并不是由这个结点所对应的字符串所生成的。打个比方:我添加了“memset”字符串,m->e结点已经生成,但我查找“me”时,这个字符串是否存在呢?
因此,我们还需要开一个exist数组,用于记录一个字符串的结尾,遍历到这个结点,而且此结点exist,才能说明这个字符串存在。
-
插入字符串
基本思路是一个个字符进行比对,如果有相应的结点,就直接进入,直到找不到下一个结点时,再在这个结点上生枝。这个操作会同时用到查找的相关操作,所以可以和查找操作结合起来。注意:字符串插入成功后要把结尾的结点exist标为1。
-
查找字符串
鉴于插入操作也要用到这步,我们可以把函数的返回值设置为:如果找到字符串就返回0,否则返回最后一次匹配到的结点位置。
-
删除字符串
将本结点删除,并不代表它的树枝也要被剪掉,所以直接查找字符串末尾的结点位置,exist标记为0即可。
另外:生成的结点可以被压缩,比如某些经常出现的词缀可以被压缩成一个结点,这样的编程复杂度的确不小,但是可以节省不少的空间。
1635: 图书管理
时间限制: 1 Sec 内存限制: 64 MB题目描述
图书管理是一件十分繁杂的工作,图书馆每天都会有许多新书缴入,为了更方便管理图书(以便于帮助想要结束的客人快速查找是否有他们所需要的书),我们需要设计一个图书朝着系统,该系统需要支持两种操作:
1)add(s),表示新加入一本书名为s的图书;
2)find(s),表示查询是否存在一本书名为s的图书;
输入
第一行包括一个正整数n(n≤10000),表示操作数。
以下n行,每行所给出两个操作中的一种,指令格式为:
add s
find s
在书名s与指令间有一个空格,保证书名长度都不超过200,可以加上读入数据是准确无误的。
输出
对于每个find指令,对应输出一行yes或no,表示该书是否存在。注意:开始时图书馆没有一本书,另外书名区分大小写。
样例输入
4
add Inside C#
find Effective Java
add Effective Java
find Effective Java
样例输出
no
yes
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX=3000000;
char str[220],data[MAX],kind[5];
int first[MAX],nxt[MAX],go[MAX],exist[MAX],pnum=1,arcnum;
void addarc(int a,int b){
nxt[++arcnum]=first[a];
first[a]=arcnum;
go[arcnum]=b;
}
int u,len;
int Find(int len){//如果查找到就返回0 未找到时返回第一位未匹配的位置
int v,nextpoi;
u=1;
for(int i=1;i<=len;i++){
nextpoi=-1;
for(int p=first[u];p!=0;p=nxt[p]){
v=go[p];
if(data[v]==str[i]){
nextpoi=v;
break;
}
}
if(nextpoi!=-1) u=nextpoi;
else return i;//在i位置时匹配错误
}
if(!exist[u]) return len+1;//虽然有结点,但是没有存数据
return 0;//成功找到字符串
}
void Insert(int t){//从字符串的t位置开始插入
if(t==len+1){//有结点,但是没有数据
exist[u]=1;
return;
}
for(int i=t;i<=len;i++){
addarc(u,++pnum);
data[pnum]=str[i];
u=pnum;
}
exist[u]=1;//标记当前字符串的结尾
}
int main(){
// freopen("in.txt","r",stdin);
int n,t,maxx=-1;
scanf("%d",&n);
for(int i=1;i<=n;i++){//将字符串插入字典树
scanf("%s",kind); getchar();
gets(str+1);
len=strlen(str+1);
if(kind[0]=='a')
Insert(Find(len));
else{
t=Find(len);
if(t==0) printf("yes\n");
else printf("no\n");
}
}
return 0;
}