我有一台有1mb内存的电脑,没有其他本地存储。我必须使用它通过TCP连接接受100万个8位十进制数字,对它们进行排序,然后通过另一个TCP连接发送排序的列表。

数字列表可能包含重复的,我不能丢弃。代码将放在ROM中,所以我不需要从1 MB中减去我的代码的大小。我已经有了驱动以太网端口和处理TCP/IP连接的代码,它需要2 KB的状态数据,包括1 KB的缓冲区,代码将通过它读取和写入数据。这个问题有解决办法吗?

问答来源:

slashdot.org

cleaton.net


当前回答

我在这里的建议很大程度上归功于Dan的解决方案

首先,我假设解决方案必须处理所有可能的输入列表。我认为流行的答案并没有做出这样的假设(在我看来这是一个巨大的错误)。

众所周知,任何形式的无损压缩都不会减小所有输入的大小。

所有流行的答案都假设它们能够有效地应用压缩来允许它们有额外的空间。事实上,一个足够大的额外空间块,以未压缩的形式保存他们部分完成的列表的一部分,并允许他们执行排序操作。这只是一个糟糕的假设。

对于这样的解决方案,任何了解如何进行压缩的人都能够设计一些不能很好地压缩该方案的输入数据,并且“解决方案”很可能会由于空间不足而崩溃。

相反,我采用数学方法。我们可能的输出是所有长度为LEN的列表,由0..MAX范围内的元素组成。这里LEN是1,000,000,MAX是100,000,000。

对于任意的LEN和MAX,编码此状态所需的比特数为:

Log2(MAX multichoice LEN)

因此,对于我们的数字,一旦我们完成了接收和排序,我们将需要至少Log2(100,000,000 MC 1,000,000)位来存储我们的结果,以一种能够唯一区分所有可能输出的方式。

这是~= 988kb。所以我们有足够的空间来存放结果。从这个角度来看,这是可能的。

[删除了无意义的漫谈,现在有更好的例子…]

最好的答案在这里。

另一个很好的答案是这里,它基本上使用插入排序作为函数,将列表扩展为一个元素(缓冲一些元素并进行预先排序,以允许一次插入多个元素,节省一些时间)。使用一个很好的压缩状态编码,7位增量的桶

其他回答

谷歌的(坏)方法,从HN线程。存储rle风格的计数。

你的初始数据结构是“99999999:0”(都是零,没有看到任何数字),然后假设你看到了数字3,866,344,那么你的数据结构就变成了“3866343:0,1:1,96133654:0”,你可以看到数字总是在零位数和1位数之间交替,所以你可以假设奇数代表0位,偶数代表1位。这就变成了(3866343,1,96133654)

他们的问题似乎不包括副本,但让我们假设他们使用“0:1”来表示副本。

大问题#1:1M个整数的插入将花费很长时间。

大问题#2:像所有的普通增量编码解决方案一样,一些分布不能用这种方式覆盖。例如,1m整数,距离为0:99(例如,每个整数+99)。现在考虑相同的情况,但随机距离在0:99的范围内。(注:99999999/1000000 = 99.99)

谷歌的方法既不值得(缓慢),也不正确。但要为他们辩护,他们的问题可能略有不同。

排序在这里是次要问题。正如其他人所说,仅仅存储整数是困难的,并且不能在所有输入上工作,因为每个数字需要27位。

我对此的看法是:只存储连续(排序)整数之间的差异,因为它们很可能很小。然后使用压缩方案,例如,每个输入数字增加2位,来编码数字存储在多少位上。 喜欢的东西:

00 -> 5 bits
01 -> 11 bits
10 -> 19 bits
11 -> 27 bits

在给定的内存限制内,应该能够存储相当数量的可能输入列表。如何选择压缩方案以使其在最大输入数量上工作的数学超出了我的范围。

我希望您能够利用输入的领域特定知识,在此基础上找到足够好的整数压缩方案。

哦,然后,当你收到数据时,你对那个排序的列表进行插入排序。

在10^8的范围内有10^6个值,所以平均每100个码点有一个值。存储第N个点到第(N+1)个点的距离。重复值的跳过值为0。这意味着跳跃平均需要7比特来存储,所以100万个跳跃将很适合我们的800万比特存储空间。

这些跳跃需要被编码成一个比特流,比如通过霍夫曼编码。插入是通过遍历比特流并在新值之后重写。通过遍历并写出隐含值来输出。出于实用性考虑,它可能被做成10^4个列表,每个列表包含10^4个代码点(平均100个值)。

随机数据的霍夫曼树可以通过假设跳跃长度上的泊松分布(均值=方差=100)先验地构建,但可以在输入上保留真实的统计数据,并用于生成处理病理病例的最佳树。

我将利用TCP的重传行为。

让TCP组件创建一个大的接收窗口。 收到一定数量的包,但没有发送ACK。 处理这些传递,创建一些(前缀)压缩数据结构 对最后一个不再需要的数据包发送重复的ack /等待重传超时 转到2 所有数据包被接受

这假设了桶或多次传递的某种好处。

可能是通过对批次/桶进行排序并合并它们。->根树

使用这种技术接受并排序前80%,然后读取后20%,验证后20%不包含将落在最低数字的前20%的数字。然后发送最低的20%的数字,从内存中删除,接受剩下的20%的新数字并合并。**

在所有可能的输入中,这个问题只有一个解决方案。作弊。

通过TCP读取m个值,其中m接近内存中可排序的最大值,可能是n/4。 对250,000(大约)个数字进行排序并输出。 重复做另外3个四分之三。 让接收方在处理时合并接收到的4个数字列表。(这并不比使用单个列表慢多少。)