PAT trie
最近在上计算机应用编程,老师给了一个大小为900MB的含20000000行邮箱地址的文件。 然后再给出了1000条查询数据,让你用字典树建树然后查询是否出现过。
试了下普通的tire树,特意用二进制写了下,结果才建了300000的时候就快用了2G内存,根本不行。
后面学习了下 PAT trie,发现确实是好东西,已经几乎达到最优内存了,如果有N个记录,那么只需要2*N个节点即可建成字典树。
算法的关键在于先将记录用一串二进制位表示,然后在建树的时候只在一些具有区别作用的二进制位进行节点分裂。
具体见http://hxraid.iteye.com/blog/615295,这篇博客讲的比较详细。
这里给出我用C++实现的代码。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
using namespace std;
#define MAXLEN 1000000000LL
#define N 20020000
struct node
{
int l,r;
int pos;
bool flag;//用来标记是否是叶子节点
int end_point;//指向叶子节点.
}g[*N]; char saveword[MAXLEN];
int word_pos[N];
short int word_len[N];
int n;
char str[];
int len;
int cnt;
char qest[][];
bool flag_ans[]; void build_tree(int s,int head)
{
if(g[head].flag==)//表示叶子结点
{
int tn=g[head].end_point;
int num=(s>>);
int other=(s&);
int ta,tb;
while()
{
if(num>=len) break;
ta=(str[num]&(<<(-other)) );
tb=(saveword[(word_pos[tn]+num)]&(<<(-other)));
if( ta!=tb )
{
//开始分裂
g[cnt]=g[head];
cnt++;
g[head].flag=;
g[head].pos=(num<<)+other;
if(tb==)
g[head].l=cnt-;
else g[head].r=cnt-;
g[cnt].end_point=n;
g[cnt].flag=;
cnt++;
if(ta!=)
g[head].r=cnt-;
else g[head].l=cnt-;
break;
}
other++;
if(other==)
{
num++;
other=;
}
}
}
else
{
int tn=g[head].end_point;
int tpos=g[head].pos;
int num;
int other;
int ta,tb;
for(int i=s;i<tpos;i++)
{
num=(i>>);
other=(i&);
ta=(str[num]&(<<(-other)) );
tb=(saveword[(word_pos[tn]+num)]&(<<(-other)));
if(ta!=tb)//ta!=tb
{
g[cnt]=g[head];
cnt++;
g[head].flag=;
g[head].pos=i;
if(tb!=)
g[head].r=cnt-;
else g[head].l=cnt-;
g[cnt].flag=;
g[cnt].end_point=n;
cnt++;
if(ta!=) g[head].r=cnt-;
else g[head].l=cnt-;
return ;
}
}
num=(tpos>>);
other=(tpos&);
ta=(str[num]&(<<(-other)) );
if(ta==)
{
build_tree(tpos+,g[head].l);
}
else build_tree(tpos+,g[head].r);
}
} int check_tree(int s)
{
if(g[s].flag==)
{
int tn=g[s].end_point;
if(len!=word_len[tn]) return ;
for(int i=;i<len;i++)
{
if(str[i]!=saveword[ word_pos[tn]+i ]) return ;
}
return ;
}
int tpos=g[s].pos;
int num=(tpos>>);
int other=(tpos&);
int ta;
ta=(str[num]&(<<(-other)) );
if(ta!=) return check_tree(g[s].r);
else return check_tree(g[s].l);
} void check()
{
//freopen("G:\\session1\\checklist.dat","r",stdin);
//cin>>T;
//getchar(); //int ansans=0;
for(int i=;i<;i++)
{
strcpy(str,qest[i]);
len=strlen(str);
str[len]='#';
len++;
str[len]=;
for(int j=;j<len;j++)
{
if(str[j]>='A'&&str[j]<='Z')
str[j]=str[j]-'A'+'a';
}
int sign1=check_tree();
//ansans+=sign1;
if(sign1==)
flag_ans[i]=;
//if(sign1==1) printf("%s\n",str);
//T--;
//if(T==0) break;
}
} int main()
{
freopen("checklist.dat","r",stdin);
freopen("checkedresult.dat","w",stdout);
int tcnt=;
while(scanf("%s",qest[tcnt])!=EOF) tcnt++;
//printf("%d\n",tcnt);
freopen("emaillist.dat","r",stdin);
//int T;
//cin>>T;
//getchar();
n=;
cnt=;
int first_flag=;
int tmp_pos=;
int cntt=;
while(scanf("%s",str)!=EOF)
{
cntt++;
if(cntt==)
{
char tstr[];
strcpy(tstr,str);
check();
cnt=;
n=;
first_flag=;
tmp_pos=;
strcpy(str,tstr);
}
word_pos[n]=tmp_pos;
len=strlen(str);
str[len]='#';
len++;
word_len[n]=len;
for(int i=;i<len;i++)
{
if(str[i]>='A'&&str[i]<='Z')
str[i]=str[i]-'A'+'a';
saveword[tmp_pos++] = str[i];
}
//然后就是构树了
if(first_flag==)
{
first_flag=;
g[].flag=;//为n号叶子结点。
g[].end_point=n;
cnt++;
}
else
{
build_tree(,);
}
n++;
//if(n%100000==0) printf("%d\n",n); //T--;
//if(T==0) break;
}
check();
int ansans=;
for(int i=;i<;i++)
{
if(flag_ans[i]==)
printf("yes\n");
else printf("no\n");
ansans+=flag_ans[i];
}
printf("%d\n",ansans);
return ;
}
PAT trie的更多相关文章
- Leetcode: Implement Trie (Prefix Tree) && Summary: Trie
Implement a trie with insert, search, and startsWith methods. Note: You may assume that all inputs a ...
- uva 1401 dp+Trie
http://uva.onlinejudge.org/index.php? option=com_onlinejudge&Itemid=8&page=show_problem& ...
- CF #Manthan, Codefest 16 C. Spy Syndrome 2 Trie
题目链接:http://codeforces.com/problemset/problem/633/C 大意就是给个字典和一个字符串,求一个用字典中的单词恰好构成字符串的匹配. 比赛的时候是用AC自动 ...
- 可持久化 trie 的简单入门
可持久化 $trie$ ....又是一个表里不一的东西..... 可持久化 $trie$ 的介绍: 和主席树类似的,其实可持久化就是体现在前缀信息的维护上(搞不懂这怎么就叫做可持久化了...) $ ...
- poj_3987 Trie图
题目大意 有N个病毒,病毒由A-Z字母构成,N个病毒各不相同.给出一段程序P,由A-Z字母构成,若病毒在在程序P或者P的逆转字符串P'中存在,则该程序P被该病毒感染.求出程序P被多少种病毒感染. 题目 ...
- 后缀树(Suffix Trie)子串匹配结构
Suffix Trie 又称后缀Trie或后缀树.它与Trie树的最大不同在于,后缀Trie的字符串集合是由指定字符串的后缀子串构成的.比如.完整字符串"minimize"的后缀子 ...
- 标准Trie、压缩Trie、后缀Trie
ref : https://dsqiu.iteye.com/blog/1705697 1.Trie导引 Trie树是一种基于树的数据结构,又称单词查找树.前缀树,是一种哈希树的变种.应用于字符串的统计 ...
- luoguP6623 [省选联考 2020 A 卷] 树(trie树)
luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...
- 《转载》PAT 习题
博客出处:http://blog.csdn.net/zhoufenqin/article/details/50497791 题目出处:https://www.patest.cn/contests/pa ...
随机推荐
- MAC下安装Mysql数据库
步骤一:安装 登录官网:mysql数据库下载官网下载合适的版本 下载完成后,在Finder的侧边栏为下载的目录中,找到下载完成的文档. 单击下载文档,单击MySQL-5.6.22-osx10.8-x8 ...
- 倍福TwinCAT(贝福Beckhoff)应用教程13.2 TwinCAT控制松下伺服 CS说明
虚拟仿真上,要注意仿真只是为了可视化,可以看到数据的变动是否和实际一致,所以Robot2D才是主要因素,虚拟仿真采集机器人的关节位置或者TCP位置来显示而已,为了测试一些别的算法,我们还可以在虚拟仿真 ...
- Linux启动U盘制作
Linux目前最好的u盘启动工具之一,下面介绍它的用法,首先下载Linux live OK了,一步一步跟我步骤走! 启动时,选择需要用的U盘 步骤二,就选择安装源即可(一般为ISO文件) 最后进行步骤 ...
- 利用Json_encode解决中文问题
利用Json_encode解决中文问题 public function return_json($data=array()){ echo json_encode($data ...
- XML之Schema
前面学习了DTD.相同我们有了一套更完好的定义法则-Schema. 以下环绕Schema是什么.为何用以及怎么用谈谈自己的感受. XML Schema是基于XML的DTD替代者. XML Schema ...
- VirtualBox实现宿主机和虚拟机之间网络的通讯
摘要:实现宿主机和虚拟机之间网络的通讯 环境: 宿主机操作系统 WindowsXP 虚拟机软件 VirtualBox 虚拟机操作系统 ...
- Idea Cannot import to svn: Cannot run program "svn"
svn 出此问题:意味着不可检出代码. 按此修改,重启IDEA即可检出svn代码.
- XX年年终总结---重新飞跃
XX年年终总结---重新飞跃 写之前先解释一下为什么是年终总结,由于在提高班学习,每年结束于暑假:新的一年開始于9月. 肚子里的墨水已经找不到新的词语来形容时间过得快了,一年结束了.还有一年又结束了: ...
- sql server 常用函数 及 方法
返回受上一语句影响的行数: @@ROWCOUNT 语法@@ROWCOUNT 返回类型integer 注释任何不返回行的语句将这一变量设置为 0 ,如 IF 语句. 示例下面的示例执行 UPDATE 语 ...
- linux下 目录(扩容)挂载磁盘
1.常用命令 查看硬盘的分区 #sudo fdisk -l 查看IDE硬盘信息 #sudo hdparm -i /dev/hda 查看STAT硬盘信息 #sudo hdparm -I /dev/sda ...