POJ 2503 - 字典树再解

1.Question:

题意:
有不超过10w个字典序列,每个字典序列中都是两个字符串,第一个字符串是英文,第二个字符串是对应的一门不知道什么语言
现在要求我们尽可能快速的建立映射,是的我们根据输入的外语可以快速的查找到对应的英语
每个单词的长度不超过10,全部都是小写(简化了问题)

输入样例和解释:
dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay

atcay
ittenkay
oopslay
第一个序列代表我们的字典序列
之后的一个空行之后我们开始执行查找操作,输入一直执行到文件的末尾

2.Solution:

本题的思路很多,因为是查找类的题目:
通解有:字典树,快排+二分,字符串哈希
本文只针对字典树的解法,快排和哈希我另外再写解法

对于字典树,如果还没有了解,欢迎访问我的博客: lantian的字典树总结
首先对于本题来说,因为是OJ上的题目,我们对速度是要非常的小心的,所以这里我们摒弃查找速度相对较慢的双链法实现的字典树,我们采用类似B树的形式构建多键字典树

字典树的节点内容:
typedef struct node
{
	char key;   //存储当前的键位 
	struct node* nextp[27];   //子指针 
	char* data;   //存储字典键值 
	bool isleaf;   //判断域是否是叶子节点
	bool isphrase;   //判断以当前键结束的词是否出现过 
}point;
这里的isphrase是非常的有必要的,在总结中我已经提到了,我们的字典树采用的是公共前缀的压缩处理方式所以说我们真的很有必要判断当前的节点是不是一个单词的末尾

PS:在这里为了节约内存我稍微做了点优化,我将存储字符串的变量没有设置成数组,我设置成了字符指针,对于非叶子节点只占用一个字节的内存,只有对于叶子节点才会保存长的字符串

3.Code:

相对高效存储的(因为考虑的建树的时间,字典树的速度会稍微的慢于字符串哈希)哈希算法而言,我们的字典树是稍微,慢了的,但是还算是非常的高效

/*
Problem: 2503		User: lantianheyeqi
Memory: 20760K		Time: 516MS
Language: C++		Result: Accepted
*/
#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"

using namespace std;

typedef struct node
{
	char key;   //存储当前的键位 
	struct node* nextp[27];   //子指针 
	char* data;   //存储字典键值 
	bool isleaf;   //判断域是否是叶子节点
	bool isphrase;   //判断以当前键结束的词是否出现过 
}point;

point root;   //根节点,根节点没有键值 
int number;  //节点总数
char english[13];
char foreign[13];

void initpoint(point& x,char key)    //初始化节点 
{
	x.key=key;
	for(int i=0;i<27;i++) x.nextp[i]=NULL;
	x.data=NULL;
	x.isleaf=true;
	x.isphrase=false;
}

void insert()
{
	point* help=&root; 
	char* now=foreign;
	while(*now!='\0')
	{
		if(help->nextp[(*now-'a')]!=NULL) help=help->nextp[(*now-'a')];
		else
		{
			point* p=new point;
			initpoint(*p,*now);
			if(*(now+1)!='\0') p->isleaf=false;   //强制转化非叶子节点 
			else 
			{
				p->isphrase=true;    //强制转化成单词节点
				p->data=(char*)malloc(sizeof(char)*12);
				strcpy(p->data,english);
			} 
			help->nextp[(*now-'a')]=p;
			help=p;
		}
		now++;
	}
}

void find()
{
	point* p=&root;
	char* now=foreign;
	while(*now!='\0')
	{
		if(p==NULL) break;
		p=p->nextp[(*now-'a')];
		now++;
	}
	if(p==NULL) printf("eh\n");
	else printf("%s\n",p->data);
}

int main()
{
	char ppp[30];
	initpoint(root,'#');
	while(gets(ppp) && ppp[0]!='\0')
	{
		sscanf(ppp,"%s %s",&english,foreign);
		insert();   //插入操作
		number++; 
		memset(english,0,sizeof(english));
		memset(foreign,0,sizeof(foreign));
	}
	
	while(gets(foreign))
	{
		find();
		memset(foreign,0,sizeof(foreign));
	}
	return 0;
} 



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值