careercup-扩展性和存储限制10.3

题目

给你一个文件,里面包含40亿个整数,写一个算法找出该文件中不包含的一个整数, 假设你有1GB内存可用。

如果你只有10MB的内存呢?

解答

我们先来做个算术题,40亿个整数大概有多大?

40 * 10^8 * 4B = 16GB (大约值,因为不是按照2的幂来做单位换算)

这个明显无法一次性装入内存中。但是,如果我们用计算机中的一位来表示某个数出现与否, 就可以减少内存使用量。比如在一块连续的内存区域,15出现,则将第15位置1。 这个就是Bit Map算法。关于这个算法,网上有篇文章写得挺通俗易懂的,推荐:

http://blog.csdn.net/hguisu/article/details/7880288

如果用Bit Map算法,一个整数用一位表示出现与否,需要的内存大小是:

40 * 10^8 b = 5 * 10^8 B = 0.5GB

而我们有1GB的内存,因此该算法可行。由于Bit Map只能处理非负数, (没有说在第-1位上置1的),因此对于有符号整数,可以将所有的数加上0x7FFFFFFF, 将数据移动到正半轴,找到一个满足条件的数再减去0x7FFFFFFF即可。 因此本文只考虑无符号整数,对于有负数的情况,按照上面的方法处理即可。

我们遍历一遍文件,将出现的数对应的那一位置1,然后遍历这些位, 找到第一个有0的位即可,这一位对应的数没有出现。代码如下:

#include <iostream>
#include <cstdio>
using namespace std;

int main(){
    // freopen("12.3.in", "w", stdout);
    // int miss = 12345;
    // for(int i=0; i<20000; ++i){
    //     if(i == miss) continue;
    //     cout<<i<<endl;
    // }
    // fclose(stdout);

    freopen("12.3.in", "r", stdin);

    int int_len = sizeof(int) * 8;
    int bit_len = 0xFFFFFFFF / int_len;
    int* bit = new int[bit_len];
    int v;
    while(scanf("%d", &v) != EOF){
        bit[v/int_len] |= 1<<(v%int_len);
    }
    bool found = false;
    for(int i=0; i<bit_len; ++i){
        for(int j=0; j<int_len; ++j){
            if((bit[i] & (1<<j)) == 0){
                cout<<i*int_len + j<<endl;
                found = true;
                break;
            }

        }
        if(found) break;
    }

    delete[] bit;
    fclose(stdin);
    return 0;
}

 

而我们有1GB的内存,因此该算法可行。由于Bit Map只能处理非负数, (没有说在第-1位上置1的),因此对于有符号整数,可以将所有的数加上0x7FFFFFFF, 将数据移动到正半轴,找到一个满足条件的数再减去0x7FFFFFFF即可。 因此本文只考虑无符号整数,对于有负数的情况,按照上面的方法处理即可。

接下来我们就可以用Bit Map算法了。我们再遍历一遍数据, 把落在这个块的数对应的位置1(我们要先把这个数归约到0到blocksize之间)。 最后我们找到这个块中第一个为0的位,其对应的数就是一个没有出现在该文件中的数。 代码如下:

#include <iostream>
#include <cstdio>
using namespace std;

int main(){
    freopen("12.3.in", "r", stdin);// 20000 number
    int int_len = sizeof(int) * 8;
    int totalnum = 20000;
    int blocksize = 2000;
    int blocknum = totalnum / blocksize;
    int* block = new int[blocknum];
    int* bit = new int[blocksize/int_len+1];
    int v;
    while(scanf("%d", &v) != EOF){
        ++block[v/blocksize];
    }
    fclose(stdin);
    int start;
    for(int i=0; i<blocknum; ++i){
        if(block[i] < blocksize){
            start = i * blocksize;
            break;
        }
    }
    freopen("12.3.in", "r", stdin);
    while(scanf("%d", &v) != EOF){
        if(v>=start && v<start+blocksize){
            v -= start; // make v in [0, blocksize)
            bit[v/int_len] |= 1<<(v%int_len);
        }
    }

    bool found = false;
    for(int i=0; i<blocksize/int_len+1; ++i){
        for(int j=0; j<int_len; ++j){
            if((bit[i] & (1<<j)) == 0){
                cout<<i*int_len+j+start<<endl;
                found = true;
                break;
            }
        }
        if(found) break;
    }

    delete[] block;
    delete[] bit;
    fclose(stdin);
    return 0;
}

 

posted @ 2015-04-23 09:18  Jessica程序猿  阅读(308)  评论(0编辑  收藏  举报