我认为 Airza 的解决方案正朝着一个好的方向发展,但由于排序不是您想要的,而且成本更高,您可以结合 angelatlarge 的方法执行以下操作:
取一个适合大小为 M/2 的内存的块 C 。
获取块 C i
遍历i并将每个元素散列到散列表中。如果元素已经存在,那么您就知道它是重复的,您可以将其标记为重复。(将其索引添加到数组或其他东西中)。
获取下一个块 C i+1 并检查哈希表中是否已存在任何键。如果元素存在,则将其标记为删除。
对所有块重复,直到您知道它们不会包含来自块 C i的任何重复项
对块 C i+1重复步骤 1,2
删除了所有标记为要删除的元素(可以在更合适的情况下在此期间完成,如果您必须转移其他所有内容,那么一次删除一个可能会更昂贵)。
这在 O((N/M)*|C|) 中运行,其中 |C| 是块大小。请注意,如果 M > 2N,那么我们只有一个块,并且运行时间为 O(N),这对于删除重复项是最佳的。我们只需对它们进行哈希处理并确保删除所有冲突。
编辑:根据要求,我提供详细信息:* N 是电话号码。
块的大小取决于内存,它的大小应该是 M/2。这是将加载文件块的内存大小,因为整个文件太大而无法加载到内存中。
这会留下另外 M/2 个字节来保存哈希表2和/或重复列表1。
因此,应该有 N/(M/2) 个块,每个块的大小为 |C| = 米/2
运行时间将是块的数量(N/(M/2)),乘以每个块的大小|C| (或 M/2)。总的来说,这应该是线性的(加上或减去从一个块更改为另一个块的开销,这就是为什么描述它的最佳方式是 O( (N/M) * |C| )
一个。加载一个块 C i。O(|C|)
b. 遍历每个元素,测试并设置如果不存在O(1)将在其中插入和查找应该进行散列。
C。如果元素已经存在,您可以将其删除。1
天。获取下一个块,冲洗并重复(2N/M 个块,所以O(N/M))
1移除一个元素可能会花费 O(N),除非我们保留一个列表并一次性移除它们,避免在移除一个元素时移动所有剩余的元素。
2如果电话号码都可以表示为小于 2 32 - 1 的整数,我们可以避免使用完整的哈希表,而只需使用标志映射,从而节省大量内存(我们只需要 N 位内存)
这是一个有点详细的伪代码:
void DeleteDuplicate(File file, int numberOfPhones, int maxMemory)
{
//Assume each 1'000'000 number of phones that fit in 32-bits.
//Assume 2MB of memory
//Assume that arrays of bool are coalesced into 8 bools per byte instead of 1 bool per byte
int chunkSize = maxMemory / 2; // 2MB / 2 / 4-byes per int = 1MB or 256K integers
//numberOfPhones-bits. C++ vector<bool> for example would be space efficient
// Coalesced-size ~= 122KB | Non-Coalesced-size (worst-case) ~= 977KB
bool[] exists = new bool[numberOfPhones];
byte[] numberData = new byte[chunkSize];
int fileIndex = 0;
int bytesLoaded;
do //O(chunkNumber)
{
bytesLoaded = file.GetNextByes(chunkSize, /*out*/ numberData);
List<int> toRemove = new List<int>(); //we still got some 30KB-odd to spare, enough for some 6 thousand-odd duplicates that could be found
for (int ii = 0; ii < bytesLoaded; ii += 4)//O(chunkSize)
{
int phone = BytesToInt(numberData, ii);
if (exists[phone])
toRemove.push(ii);
else
exists[phone] = true;
}
for (int ii = toRemove.Length - 1; ii >= 0; --ii)
numberData.removeAt(toRemove[ii], 4);
File.Write(fileIndex, numberData);
fileIndex += bytesLoaded;
} while (bytesLoaded > 0); // while still stuff to load
}