算法 – 排序列表,以便相等元素之间的差距尽可能大

让我们假设我有一个未分类的List包含a,a,b,b,a,c,我想要对这个序列进行排序,以便相等元素之间的间隙尽可能大.因此,在该样本序列的情况下,可能的输出可以是b,a,c,a,b,a.在我的应用中,间隙达到其精确的平均最大值并不重要,但只要有可能,就不应该有两个相等的元素彼此相邻.所以我的压力是最大化最小的差距.
最佳答案
我从测量每个独特元素的频率开始:

scala> val l = List("a", "a", "b", "b", "a", "c")
l: List[String] = List(a, a, b, b, a, c)

scala> val in = l.toSet[String].map(x => x -> l.count(x==)).toList.sortBy(_._2).reverse
in: List[(String, Int)] = List((a,3), (b,2), (c,1))

所以现在你可以生成更少的分散列表:

def shuffle[T](l: List[T]) = {

   def fill(n: Int, l: List[List[T]], s: T) = 
      l.take(n + 1).reduce(_ ++ List(s) ++ _) ++ l.drop(n + 1).flatten

   val in = l.toSet[T].map(x => x -> l.count(x==)).toList.sortBy(_._2).reverse

   val initial = in.head._2 -> List.fill(in.head._2)(in.head._1)

   in.tail.foldLeft(initial){case ((size, acc), (value, count)) => 
     count -> fill(count, acc.grouped(acc.size / size).toList, value)
   }._2
}

scala> shuffle(l)
res32: List[String] = List(a, b, c, a, b, a)

这里的每个下一次迭代都基于前一个具有更高频率的迭代:尽可能宽地插入到列表中的元素(来自先前的迭代).因此,如果频率在迭代之间显着下降,则可能不那么有效,因为高频率元素可能不会“足够”地“缩小”.

该算法并未尝试最大化每个距离 – 它试图将分组元素外观的概率降至最低.只是随机改组应该做类似的事情,如果你没有精确的结果,因为它产生的组仍然很小,但更高的概率:

scala> scala.util.Random.shuffle(l)
res34: List[String] = List(a, b, c, b, a, a)

转载注明原文:算法 – 排序列表,以便相等元素之间的差距尽可能大 - 代码日志