Java 使用有限的内存查找缺少的号码

Java 使用有限的内存查找缺少的号码,java,algorithm,Java,Algorithm,问题是,给定一个具有40亿个唯一整数的输入文件,提供一种算法来生成文件中不包含的整数,假设只有10 MB内存 在下面搜索了一些解决方案并发布了代码,其中一个是将整数存储到位向量块中(每个块表示40亿范围中的特定整数范围,块中的每个位表示一个整数),并对每个块使用另一个计数器来计算每个块中的整数数。因此,如果整数的数量小于整数的块容量,则扫描块的位向量以查找缺少的整数 对于这个解决方案,我的问题是,为什么“我们选择的越靠近中间位置,在任何给定时间使用的内存就越少”,这里有更多的上下文 第一个过程中

问题是,给定一个具有40亿个唯一整数的输入文件,提供一种算法来生成文件中不包含的整数,假设只有10 MB内存

在下面搜索了一些解决方案并发布了代码,其中一个是将整数存储到位向量块中(每个块表示40亿范围中的特定整数范围,块中的每个位表示一个整数),并对每个块使用另一个计数器来计算每个块中的整数数。因此,如果整数的数量小于整数的块容量,则扫描块的位向量以查找缺少的整数

对于这个解决方案,我的问题是,为什么“我们选择的越靠近中间位置,在任何给定时间使用的内存就越少”,这里有更多的上下文

第一个过程中的数组可以容纳10兆字节(约2^23字节)的内存。因为数组中的每个元素都是int,int是4个字节,所以我们最多可以保存2^21个元素的数组。因此,我们可以推断如下:

因此,我们可以得出以下结论: 2^10位字段[(n-开始)/8]|=1我喜欢这个问题。我会再考虑一下,但我认为如果磁盘空间和时间不是问题,你可以将数字分成100k块,并在每个文件中进行排序。任何没有100k条目的块都会有一个间隙。这一点都不优雅,但它会让人感到高兴。

所需的总内存为M+2^27/M个字(32位)。当M=√2^27,介于1和2^27块之间。最小值为2^14.5个字,约92 KB

这在双对数图上非常清楚


你的问题是为什么在2%之间⁰ 和2²⁶ 占用更少的内存?文件是否有40亿个唯一整数?或者,是否有可能重复?您忘记了清楚地说明您的问题。阅读您的帖子后,我只能想“这很有趣,但您在问什么?”数字是唯一的吗?除了缺少的一个之外,它们是连续的吗?因为int范围在-2b到+2b之间,并且你说集合是不同的,负数必须存在,对吗?因此这会导致在第一个while循环中使用负数组索引eval。感谢Yves,你如何获得
M+2^27/M
字(32位)?@LinMa:每组一个32位计数器和2^32/M位。@LinMa:是的,我写的。@LinMa:例如。@LinMa:对不起,我不再在这上面花费时间了。谢谢ajacian81,我们也非常感谢您对内存利用率的见解。:)
public class QuestionB {
    public static int bitsize = 1048576; // 2^20 bits (2^17 bytes)
    public static int blockNum = 4096; // 2^12
    public static byte[] bitfield = new byte[bitsize/8];
    public static int[] blocks = new int[blockNum];

    public static void findOpenNumber() throws FileNotFoundException {
        int starting = -1;
        Scanner in = new Scanner (new FileReader ("Chapter 10/Question10_3/input_file_q10_3.txt"));
        while (in.hasNextInt()) {
            int n = in.nextInt();
            blocks[n / (bitfield.length * 8)]++;
        }

        for (int i = 0; i < blocks.length; i++) {
            if (blocks[i] < bitfield.length * 8){
                /* if value < 2^20, then at least 1 number is missing in
                 * that section. */
                starting = i * bitfield.length * 8;
                break;
            }
        }

        in = new Scanner(new FileReader("Chapter 10/Question10_3/input_file_q10_3.txt"));
        while (in.hasNextInt()) {
            int n = in.nextInt();
            /* If the number is inside the block that’s missing 
             * numbers, we record it */
            if (n >= starting && n < starting + bitfield.length * 8) {
                bitfield [(n-starting) / 8] |= 1 << ((n - starting) % 8);
            }
        }

        for (int i = 0 ; i < bitfield.length; i++) {
            for (int j = 0; j < 8; j++) {
                /* Retrieves the individual bits of each byte. When 0 bit 
                 * is found, finds the corresponding value. */
                if ((bitfield[i] & (1 << j)) == 0) {
                    System.out.println(i * 8 + j + starting);
                    return;
                }
            }
        }       
    }

    public static void main(String[] args) throws FileNotFoundException {
        findOpenNumber();
    }

}