Algorithm 寻找一个有限的洗牌算法

Algorithm 寻找一个有限的洗牌算法,algorithm,random,shuffle,array-algorithms,Algorithm,Random,Shuffle,Array Algorithms,我洗牌有问题。有很多页面和讨论关于完全洗牌一系列值,比如一堆卡片 我需要的是一个洗牌,它将均匀地将数组元素从其起始位置移开最多N个位置 也就是说,如果N是2,那么元素I最多将被洗牌到从I-2到I+2的位置(在数组的边界内) 事实证明,对于一些简单的解决方案来说,这是一个棘手的问题,这些解决方案会导致元素移动的方向性偏差,或者导致偏移量不均匀。你说得对,这是一个棘手的问题!首先,我们需要建立更多的规则,以确保我们不会产生人为的非随机结果: 元素可以保留在它们开始的位置。这是任何公平洗牌的必要部分

我洗牌有问题。有很多页面和讨论关于完全洗牌一系列值,比如一堆卡片

我需要的是一个洗牌,它将均匀地将数组元素从其起始位置移开最多N个位置

也就是说,如果N是2,那么元素I最多将被洗牌到从I-2到I+2的位置(在数组的边界内)


事实证明,对于一些简单的解决方案来说,这是一个棘手的问题,这些解决方案会导致元素移动的方向性偏差,或者导致偏移量不均匀。

你说得对,这是一个棘手的问题!首先,我们需要建立更多的规则,以确保我们不会产生人为的非随机结果:

  • 元素可以保留在它们开始的位置。这是任何公平洗牌的必要部分,也确保了我们的洗牌在N=0时有效
  • 当N大于元素到数组起点或终点的距离时,允许将其移动到另一侧。我们可以调整算法来禁止这样做,但这将违反“统一”要求——靠近两端的元素比靠近中间的元素更可能保持不变
现在我们可以解决这个问题了

  • i+[-N,N]
    范围内生成一个随机值数组,其中
    i
    是数组中的当前索引。规范化数组边界以外的值(例如,
    -1
    应变为
    length-1
    length
    应变为
    0
  • 在数组中查找重复值对(冲突),然后重新计算它们。您有几个选择:
    • 重新计算这两个值,直到它们彼此不冲突,否则它们仍可能与其他值冲突
    • 只重新计算一个值,直到它与另一个值不冲突为止,第一个值仍然可能冲突,但第二个值现在应该是唯一的,这可能意味着对RNG的调用更少
    • 确定每次碰撞的可用索引集(例如,在
      [3,1,1,0]
      索引
      2
      中可用),从该集中选择一个随机值,并将其中一个数组值设置为选定结果。这避免了在冲突解决之前需要循环,但编码更复杂,并且有可能遇到集合为空的情况
  • 无论如何处理单个冲突,请重复该过程,直到数组中的每个值都是唯一的
  • 现在将原始数组中的每个元素移动到我们生成的数组中指定的索引
  • 我不确定如何最好地实施#2,我建议您对其进行基准测试。如果您不想花时间进行基准测试,我会选择第一个选项。其他的优化可能会更快,但最终可能会更慢


    该解决方案在理论上有一个无限的运行时,但在实践中应该很快终止。同样,在任何关键的地方使用它之前,先对它进行基准测试和测试。

    我提出了一个可能的解决方案,尽管我不确定它有多“幼稚”。尤其是在边缘,尤其是远边缘

  • 创建一个N长(表示已交换的元素)的标志(布尔)数组

  • 对于每个索引检查是否已交换(根据flags数组中的第一个元素),如果已交换,请转到下一个(见下文)

  • 旋转flags数组,删除第一个元素(表示 元素),并在末尾添加一个新的“未交换”元素。旁白:这个 可能使用模数组查找来完成,以避免实际 移动数组内容,特别是对于大的N

  • 循环

    • 从0到N(或小于N,如果N加上当前值 索引大于正在洗牌的数组
    • 如果为0,则元素与自身交换,移动到下一个
    • 否则,如果该元素标记为已交换,请循环并重试。 请注意,flags数组中始终有2个元素可以自己拾取 和最后一个元素(除非接近被洗牌的数组末尾)
  • 将当前元素与选定的未交换元素交换,在标志数组中将选定元素标记为已交换。循环到下一个元素


  • 总之:在当前索引的+/-N范围内创建一个单独的随机索引数组。然后查找解决重复索引。从该位置开始,解决过程可能很困难,如果不是不可能的话。第三个选项(计算可用索引集)将在有限的时间内运行,但我不认为它实际上比一般情况下的无限选项更好。正如我所说,您需要对其进行基准测试。如果解决方案被证明不可能,可能是您的问题没有一个通用的解决方案。我很好奇您是从哪里想到这个的,或者是什么原因使您认为您需要这个行为。这让我和我的同事感到困惑,所以谢谢你提出这个问题!这实际上是一个图形问题。请看命令“ppmspread”,或ImageMagick转换选项“-spread”。在这两种情况下,源都意味着它交换像素,从而保留原始图像中的所有像素,只是被替换。然而……事实并非如此,两个图像操作符实际上都会丢失像素复制和丢失的信息。我想修复这种“幼稚”的方法,但只是简单地在处理过程中交换像素图像导致某些像素“双交换”。搜索解决方案的结果无效。请注意,如果N的大小相同(或大于)在实际数组中,洗牌基本上应该转化为数组的完全洗牌。虽然在正常使用中,N相对于数组长度应该很小。通常在1到5之间。您认为这是
    ppmspread
    /
    spread
    中的一个错误吗?您看过这些操作的源代码了吗?指向文档的链接你看到的是一个很有帮助的地方,所以我们确信我们看到的是相同的东西