2

我已经查看了关于 SO 和其他地方的各种类似问题,但我觉得有些特殊情况可能需要提出一个新问题。

这是问题:

我有一个整数数组,其中可以包含多达十亿个整数。这些数字将在 1 到 10 亿之间,但可能存在缺失值。所以每个值 32 位就足够了。我唯一想做的就是确保没有重复。当我发现第一次出现重复时,我大惊小怪并退出。这将在许多文件上完成,并且很少期望这些文件有重复。所以一般情况也经常是最坏的情况。

我知道如何在 shell 中很容易地做到这一点(在文本文件中,我将从以下位置读取整数:sort | uniq 等),大约需要 13 秒。因此,希望纯 C 智能算法会做得更好。我的想法是我在数组上使用快速(希望很容易获得)排序并迭代每个连续对的计算差异。当我找到零时,我停下来退出。

这是一个玩具示例:

1001
1002
1003
1004
1005
1003
...

我首先对数组进行排序并得到: 1001 1002 1003 1003 1004 1005 ...

然后当我看到 line3 - line4 == 0 时,我停在第四行。

如果一切顺利,那么我会默默退出,退出代码为零。

这些是我的要求/限制: 1) 我是 C 语言的初学者(只有 100 行代码)。2) 我会非常喜欢纯 C 解决方案来学习。标准库没问题。3) 如果 C++ 解决方案在减少编程时间方面非常优越,那么也请提出建议。

非常感谢。

4

3 回答 3

2

这是散列解决方案的快速伪代码,因此您可以了解其背后的“概念”。我会尝试将其设为 C,但不要假设它已经过编译和测试。但它会很接近。

#include <iostream>
using namespace std;

const int NUM_BITS = 32;

bool noDuplicates(const int INPUT[], const int SIZE, const int MIN_VALUE, const int MAX_VALUE) {

    const unsigned int RANGE = (MAX_VALUE - MIN_VALUE) / NUM_BITS;  //Use unsigned int, can support wider ranges this way.

    int isPresent[RANGE];// Might need dynamic allocation here, don't know if C supports this type of array initialization

    for(int i = 0; i < RANGE; i++) isPresent[i] = 0;//Probably don't need this loop on most systems.  Aslo, there are faster ways to zero memory.

    for(int i = 0; i < SIZE; i++) {

        const int ADJUST_TO_ZERO = INPUT[i] - MIN_VALUE; //adjust our min value to zero index now every possible value should map to an indice in our "isPresent" array
        const int INT_IN_ARRAY = ADJUST_TO_ZERO / NUM_BITS; // Each int represents 32 values, or our bit is hiding in the (VALUE/32)th slot
        const unsigned int BIT_VALUE = 1 << (ADJUST_TO_ZERO % NUM_BITS); // This is identical to 2 ^ (ADJUST_TO_ZERO % NUM_BITS)

        cout << "CHECKING: " << ADJUST_TO_ZERO << " ARRAY INDEX: " << INT_IN_ARRAY << " BIT:" << (ADJUST_TO_ZERO % NUM_BITS) << " INT REPRESENTATION: " << BIT_VALUE << endl;

        if(isPresent[INT_IN_ARRAY] & BIT_VALUE) { //bitwise &, with a value 2 ^ BIT, isolates this "BIT"
            return false;
        }

        isPresent[ADJUST_TO_ZERO / NUM_BITS] += BIT_VALUE; //If we add 2^BIT to an int, we are only adding the value to this to set this "BIT"
    }
    return true; //If we escape the loop above there are no duplicates
}


int main() {
    const int SIZE = 65;
    int array[SIZE];

    for(int i = 0; i < SIZE; i++) {
        array[i] = i;
    }

    array[SIZE - 1] = 30;

    cout << "RESULT: " << noDuplicates(array, SIZE, 0, 100) << endl;
}
于 2013-06-04T13:25:01.327 回答
1

你没有说你的值的范围是什么,但假设它是 32 位整数的范围,位图数组将是 512MB,这将适合大多数现代机器而没有太多麻烦。尝试这样的事情:

/* Assumes 32-bit ints */
int verify_unique( <data source> ) {
    unsigned int *bitmap = calloc(128 * 1024 * 1024, 4);
    if (!bitmap) { <error> }

    while ( <more input> ) {
        unsigned int value = <next value>;
        unsigned int index = value >> 5;
        unsigned int mask = 1 << (value & 0x1f);

        if (bitmap[index] & mask) {
            <found duplicate>
            break;
        }
        bitmap[index] |= mask;
    }
    free(bitmap);
}
于 2013-06-04T15:39:40.513 回答
0

尝试对数组进行计数排序,然后执行 link3 减去 link4 方法。应该足够有效。

于 2013-06-04T13:19:40.197 回答