最近在上计算机应用编程,老师给了一个大小为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的更多相关文章

  1. Leetcode: Implement Trie (Prefix Tree) && Summary: Trie

    Implement a trie with insert, search, and startsWith methods. Note: You may assume that all inputs a ...

  2. uva 1401 dp+Trie

    http://uva.onlinejudge.org/index.php? option=com_onlinejudge&Itemid=8&page=show_problem& ...

  3. CF #Manthan, Codefest 16 C. Spy Syndrome 2 Trie

    题目链接:http://codeforces.com/problemset/problem/633/C 大意就是给个字典和一个字符串,求一个用字典中的单词恰好构成字符串的匹配. 比赛的时候是用AC自动 ...

  4. 可持久化 trie 的简单入门

    可持久化 $trie$  ....又是一个表里不一的东西..... 可持久化 $trie$  的介绍: 和主席树类似的,其实可持久化就是体现在前缀信息的维护上(搞不懂这怎么就叫做可持久化了...) $ ...

  5. poj_3987 Trie图

    题目大意 有N个病毒,病毒由A-Z字母构成,N个病毒各不相同.给出一段程序P,由A-Z字母构成,若病毒在在程序P或者P的逆转字符串P'中存在,则该程序P被该病毒感染.求出程序P被多少种病毒感染. 题目 ...

  6. 后缀树(Suffix Trie)子串匹配结构

    Suffix Trie 又称后缀Trie或后缀树.它与Trie树的最大不同在于,后缀Trie的字符串集合是由指定字符串的后缀子串构成的.比如.完整字符串"minimize"的后缀子 ...

  7. 标准Trie、压缩Trie、后缀Trie

    ref : https://dsqiu.iteye.com/blog/1705697 1.Trie导引 Trie树是一种基于树的数据结构,又称单词查找树.前缀树,是一种哈希树的变种.应用于字符串的统计 ...

  8. luoguP6623 [省选联考 2020 A 卷] 树(trie树)

    luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...

  9. 《转载》PAT 习题

    博客出处:http://blog.csdn.net/zhoufenqin/article/details/50497791 题目出处:https://www.patest.cn/contests/pa ...

随机推荐

  1. [TypeScript] Create Explicit and Readable Type Declarations with TypeScript mapped Type Modifiers

    Using the optional “+” sign together with mapped type modifiers, we can create more explicit and rea ...

  2. android环境部署(1)

    1.首先是eclipse(现在拿eclipse-standard-kepler-SR1-win32做实验): 下载地址:http://www.eclipse.org/downloads/downloa ...

  3. activiti入门3排他网关,并行网管,包括网关,事件网关

    网关用来控制流程的流向 网关能够消费也能够生成token. 网关显示成菱形图形,内部有有一个小图标. 图标表示网关的类型. 基本分支 首先 利用 流程变量  写个带有分支的一个基本流程 流程图: wa ...

  4. SurfaceView的经典写法

    package com.example.test; import android.content.Context; import android.graphics.Canvas; import and ...

  5. iOS 转盘动画效果实现

    代码地址如下:http://www.demodashi.com/demo/11598.html 近期公司项目告一段落,闲来无事,看到山东中国移动客户端有个转盘动画挺酷的.于是试着实现一下,看似简单,可 ...

  6. set hive.exec.parallel

    hive.exec.parallel参数控制在同一个sql中的不同的job是否可以同时运行,默认为false.下面是对于该参数的测试过程: 测试sql:select r1.a    from (sel ...

  7. Dart Essentials(读书笔记)——这本书非常大篇幅都在谈AngularDart,Zones概念没谈到

    Dart Essentials 文件夹 1 Getting Started 2 Practical Dart 3 The Power of HTML5 with Dart 4 Developing a ...

  8. iOS机型适配

           机型变化 坐标:表示屏幕物理尺寸大小,坐标变大了,表示机器屏幕尺寸变大了: 像素:表示屏幕图片的大小,跟坐标之间有个对应关系,比如1:1或1:2等: ppi:代表屏幕物理大小到图片大小的 ...

  9. Atitit. 二进制数据ascii表示法,与base64编码解码api 设计标准化总结java php c#.net

    Atitit. 二进制数据ascii表示法,与base64编码解码api 设计标准化总结java php c#.net 1. Base64编码,1 1.1. 子模式 urlsafe Or  url u ...

  10. CenterOS卸载和安装MYSQL

    1.首先在命令行输入mysql,看一下本地计算机上是否有mysql. 2.卸载mysql服务: 首先查看安装的rpm的包:rpm –qa |grep mysql    对之前的服务进行删除.rpm – ...