我有一个洗牌问题。有很多页面和讨论关于如何完全打乱数组值,就像一副卡牌。
我需要的是一种能够均匀地将数组元素最多移动N个位置的洗牌方法。
也就是说,如果N为2,则元素I最多会被洗牌到从I-2到I+2的位置(在数组边界内)。
这被证明是棘手的,因为一些简单的解决方案会导致元素移动的方向偏向某个方向,或者移动的量不均匀。
我有一个洗牌问题。有很多页面和讨论关于如何完全打乱数组值,就像一副卡牌。
我需要的是一种能够均匀地将数组元素最多移动N个位置的洗牌方法。
也就是说,如果N为2,则元素I最多会被洗牌到从I-2到I+2的位置(在数组边界内)。
这被证明是棘手的,因为一些简单的解决方案会导致元素移动的方向偏向某个方向,或者移动的量不均匀。
你说得对,这很棘手!首先,我们需要建立一些更多的规则,以确保我们不会创造人为的非随机结果:
现在我们可以实际解决问题。
i + [-N, N]
,其中 i
是数组中的当前索引。规范化超出数组范围的值(例如,-1
应变为 length-1
,而 length
应变为 0
)。[3, 1, 1, 0]
中,索引 2
可用),从该集合中选择一个随机值,并将其中一个数组值设置为所选结果。这避免了需要循环直到解决冲突,但代码更复杂,并且可能会遇到集合为空的情况。我不确定如何最好地实现#2,建议你对其进行基准测试。如果您不想花时间进行基准测试,则可以选择第一个选项。其他优化可能会更快,但实际上可能会更慢。
理论上,此解决方案的运行时间未受限制,但在实践中应该很快终止。在使用它之前,请进行基准测试和测试。
我想到了一个可能的解决方案,但它有多么“天真”,我不确定。特别是在边缘,尤其是远端。
创建一个长度为N的布尔类型标志数组(表示已经交换过的元素)
对于每个索引,检查它是否已经被交换过(根据标志数组中的第一个元素),如果是,则继续下一个(见下文)
旋转标志数组,删除第一个元素(表示这个元素),并在末尾添加一个新的“未交换”元素。附注:可以使用模数数组查找来完成此操作,以避免实际移动数组内容,特别是对于大的N。
循环...
将当前元素与选择的未交换元素交换,将选择的元素标记为已交换在标志数组中。循环到下一个元素。
ppmspread
/spread
中存在bug吗?你是否查看过这些操作的源代码?提供文档链接会很有帮助,这样我们就能确保看到的是同样的内容。 - dimo414