《编程珠玑》 二分查找在大量数据中的使用(查找一个不在文件中的数据)

《编程珠玑》第二章提到的问题A:
给定一个包含32位整数的顺序文件,它至多包含40亿个这样的整数,并且次序是随机的。请查找一个此文件不存在的32位整数。

当然,主存足够的话,我们可以使用上章提到的位图法,2^32二进制位,如果用bitset那会超过数组大小范围(即0x7fffffff),使用上章提到的int型数据转换,倒是可以实现。但是,如果内存有限,毕竟你无法一下就开辟536870912个B,太浪费资源了,不是吗?
假设,我们只有上百字节的可用内存空间,我们就要使用书中提到的二分查找法,具体原理这里不论述,下面是关键的部分:

//每次循环将初始文件转化为个数较小的数据文件
while (true)
{
s = k = 0;
//读原始数据
ifstream infile(data,ios::in|ios::_Nocreate);
if (!infile)
{
cerr<<"open error!"<<endl;
exit(1);
}
//分成两个较小文件
ofstream outfile1("file1.text",ios::out);
ofstream outfile2("file2.text",ios::out);
if (!outfile1 || !outfile2)
{
cerr<<"open error!"<<endl;
exit(1);
}
for (i = 0;i < n;++ i) //每次需读入所有数据 共n个
{
infile>>temp; //read record number
if (left <= temp && temp <= (left + right)/2)
{
s++; //left range
outfile1<<temp<<" ";
}
else //right range
{
k++;
outfile2<<temp<<" ";
}
}
infile.close();
outfile1.close();
outfile2.close();
//磁盘数据读完结束
if (s < k) //select the left side
{
right = (left + right)/2;
//生成新的较小原数据文件
ofstream outfile("temp.text",ios::out);
ifstream infile("file1.text",ios::in|ios::_Nocreate);
if (!outfile || !infile)
{
cerr<<"open error!"<<endl;
exit(1);
}
for (int i = 0;i < s;++ i)
{
infile>>temp;
outfile<<temp<<" ";
}
n = s;
outfile.close();
infile.close();
}
else
{
left = (left + right)/2; //select the right side
//生成新的较小原数据文件
ofstream outfile("temp.text",ios::out);
ifstream infile("file2.text",ios::in|ios::_Nocreate);
if (!outfile || !infile)
{
cerr<<"open error!"<<endl;
exit(1);
}
for (int i = 0;i < k;++ i)
{
infile>>temp;
outfile<<temp<<" ";
}
n = k;
outfile.close();
infile.close();
}
data = "temp.text";
if (n < SIZE)
{
break;
}
}

上述过程,每次while循环,生成一个个数较小的一半,并作为下次while循环的原始文件,这样,顺序扫描的文件从n,n/2,n/4,n/8 ....方式递减,另外,为了找到足够多的文件,并考虑到内存空间限制,我们在结果文件足够小时(即内存有效空间内,程序中的SIZE),对得到的文件采用排序算法,查找到遗漏的数据,我们这里采用了上章中提到的位图表示法:

bitset <SIZE*10> bits;
int p = 0;
ifstream infile("temp.text",ios::in|ios::_Nocreate);
cout<<"between "<<left<<" and "<<right<<endl;
for (int i = 0;i < n;++ i)
{
infile>>temp;
bits.set(temp-left);
}
infile.close();

//保存遗漏数据到result文件
ofstream outfile("result2.text",ios::out);
if(!outfile)
{
cerr<<"open error!"<<endl;
exit(1);
}
for (int i = left;i < right;++ i)
{
if (!bits.test(i-left))
{
outfile<<i<<" ";
p++;
}
}

实验中,原始数据,我们使用了前面提到的产生方法,在亿计数量级上的数据,我们大概花了5~6小时,有大概花了2~3小时找到了1000多个遗漏数据,运行内存使用控制在300KB内(任务管理器中)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值