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;
}