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 ...
随机推荐
- 常见的七大排序算法Java实现
/** * @author Javen * @Email javenlife@126.com * 2015年12月9日 */ public class Sorting { static int[] a ...
- jquery如何判断checkbox(复选框)是否被选中 全选 反选
好长时间没用jq, 之前用的都是ng. 想着随便参考一下,结果被坑.因为这篇文章是09年的,也和当时jq的版本号有关,但是为什么在百度排名第一,百度果然坑人,以后还是google 给出坑人文章的链接 ...
- HTML--百度百科
超文本标记语言,标准通用标记语言下的一个应用. “超文本”就是指页面内可以包含图片.链接,甚至音乐.程序等非文字元素. 超文本标记语言的结构包括“头”部分(英语:Head).和“主体”部分(英语:Bo ...
- LoadRunner监控tomcat
LoadRunner监控tomcat (2012-10-25 14:01:42)转载▼ double atof (const char * string);Action(){ // 保存JVM内 ...
- ActiveMQ介绍和ActiveMQ入门实例
ActiveMQ百度百科 ActiveMQ入门实例-cnblogs.com 作者用的是5.5的版本,我测试时用的是5.6,按照作者说的整了一下,走得通
- xcode7.1.1不能真机调试ios9.2系统设备的解决方法
转载自:http://www.cocoachina.com/bbs/read.php?tid-331335.html 前些天手机升级到iOS9.2版本号 xcode7.1还能真机測试. 昨晚更新xc ...
- C#实现svn server端的hook
目标 要做的东东呢,就是在向svn提交文件的时候,可以再server端读到所有提交文件的内容,并根据某些规则验证文件的合法性,如果验证失败,则终止提交,并在svn的客户端上显示错误信息. 准备工作 ...
- C++语言基础(3)-类和对象
类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量:创建对象的过程也叫类的实例化.每个对象都是类的一个具体实例(Instance),拥有类的成员变量和成员函数. 一.类的定义 一 ...
- sigpending
信号的阻塞:通过sigprocmask()将信号集sigset_t中的信号设置为阻塞.SIG_BLOCK是指对相应信号的“递送阻塞”,内核在递送一个原来被阻塞的信号给进程时(而不是在产生该信号时),才 ...
- php使用N层加密eval gzinflate str_rot13 base64 破解方法汇总
php使用N层加密eval gzinflate str_rot13 base64 破解方法汇总 来源:本站转载 作者:佚名 时间:2011-02-14 TAG: 我要投稿 PHP使用eval(gzin ...