【发布时间】:2009-12-08 12:37:28
【问题描述】:
看了this question之后,我开始怀疑:有没有可能有一个不修改或复制原始列表的洗牌算法?
说清楚:
假设你得到了一个对象列表。列表大小可以是任意的,但假设它非常大(例如,10,000,000 个项目)。您需要以随机顺序打印出列表中的项目,并且需要尽可能快地完成。但是,您不应该:
- 复制原始列表,因为它非常大,复制会浪费大量内存(可能会达到可用 RAM 的限制);
- 修改原始列表,因为它以某种方式排序,而稍后的其他部分取决于它的排序。
- 创建一个索引列表,因为列表非常大,复制需要太多时间和内存。 (澄清:这是指任何其他列表,其元素数量与原始列表相同)。
这可能吗?
添加:更多说明。
- 我希望列表以真正随机的方式随机排列,所有排列的可能性都相同(当然,假设我们有一个合适的 Rand() 函数开始)。
- 关于我创建一个指针列表、索引列表或任何其他与原始列表具有相同数量元素的列表的建议,被原始问题明确认为是低效的。您可以根据需要创建其他列表,但它们应该比原始列表小几个数量级。
- 原始列表就像一个数组,您可以通过它在 O(1) 中的索引从中检索任何项目。 (所以没有双向链表的东西,你必须遍历列表才能找到你想要的项目。)
添加 2:好的,让我们这样说吧:你有一个 1TB 的硬盘,里面装满了数据项,每个 512 字节大(一个扇区)。您想在洗牌所有项目时将所有这些数据复制到另一个 1TB 硬盘。您希望尽可能快地执行此操作(单次传递数据等)。你有 512MB 的可用 RAM,不要指望交换。 (这是一个理论上的场景,我在实践中没有这样的东西。我只是想找到完美的algorithm.item。)
【问题讨论】:
-
我认为这个问题的答案可能取决于列表的内部实现。需要明确的是,这很可能是一个双向链表,对吧?
-
paxdiablo 在这篇文章中讨论了 Knuth 的洗牌 stackoverflow.com/questions/1858610/… 我想这就是你所追求的。
-
再想一想,虽然它以 O(n) 运行,但您需要创建一个该长度的 int 数组 - 但我认为这是您可以达到的最佳效果 - 您应该以某种方式跟踪选定的项目。
-
答案是“不”,但这个空白处没有足够的空间来解释原因:-)
-
如果你破产了,你还有比洗牌更重要的事情要担心。去找工作吧:-)