这种改组算法的效率和质量如何?

时间:2008-12-17 18:01:44

标签: perl sorting random performance

最近关于sorting randomly using C#的问题让我想到了我有时在Perl中改组数组的方式。

@shuffled = sort { rand() <=> rand() } @array;

上述问题中提出的解决方案是Fisher-Yates shuffle,它在线性时间内起作用。

问题是:我的代码片段有多高效,并且是“真正”随机的混乱?

8 个答案:

答案 0 :(得分:9)

我不是Perl的内部专家,所以我不知道“sort”在这里会起作用。但是,大多数排序函数都希望它们的比较具有一致性,如果函数本身是随机的,我希望它们能够无法预测地工作。不幸的是,不可预测性与随机性不一样,所以我对你的洗牌阵列没有信心。它可能倾向于以某种顺序放置元素,就像匆忙创建和复杂的递归关系可能不是随机的一样。

我建议不要分析排序函数,而是选择Fisher-Yates。

正如Knuth所说,随机性太重要了,不值得冒险。

答案 1 :(得分:9)

$ perldoc List::Util
⋮
  shuffle LIST
       Returns the elements of LIST in a random order

           @cards = shuffle 0..51      # 0..51 in a random order
⋮

这将是我的建议。

答案 2 :(得分:8)

我实际上有点惊讶你提议的洗牌有效。在Perl sort函数的实现中,它尝试根据比较函数的值以升序获取数组的元素。问题是,你的比较函数没有返回一致的答案!有时它可能会说"foo" lt "bar",而有时可能会说"bar" lt "foo"。这可能会使排序算法混淆到永不终止的程度,或者以致命错误或其他灾难性故障结束。

答案 3 :(得分:4)

sort上的perl文档说明了这个

  

比较功能需要表现。如果它返回不一致的结果(有时说$ x [1]小于$ x [2]并且有时说相反,例如)结果没有明确定义。

这样做是个糟糕的主意。

ETA:我刚刚做了一个基准测试。在100000元素阵列上,使用FY-shuffle的速度也快10倍以上。

答案 4 :(得分:4)

首先,你知道无论你使用比较器,sort()都不可能比O(n log n)更快。因此,即使它执行的洗牌是公平的,其性能也会更差。

洗牌公平也是如此?对于一些(易于分析)排序算法来说,这显然是不公平的。考虑一个简单的冒泡排序 - 为了使一个元素从一端移动到另一端,比较函数必须评估n个连续调用的正数 - 在n个事件中应该是1的概率为1 ^ 2 ^ n。为了快速排序,很难分析,最终可能会变得公平。但是,如果它是正确的,那就做正确的方式。

答案 5 :(得分:3)

这只是直觉,但我认为使用这样的排序会产生一个集合,其顺序在某种程度上取决于原始集合的顺序。真正随机排序的结果不应完全取决于原始集合的顺序。我无法解释为什么/如何,也许其他人可以(或表明它实际上是随机的)?

至于它的效率如何,我不确定,但它可能不会比使用sort的任何其他类型效率低很多,因为AFAIK rand()相对便宜。不过我可能错了。

答案 6 :(得分:3)

有一个更好的Fisher-Yates shuffle函数,它不使用perlfaq4: How do I shuffle an array randomly?中内置的sort

答案 7 :(得分:0)


@shuffled = map {
  $_->[1]
} sort {
  $a->[0] <=> $b->[0]
} map {
  [ rand(), $_ ]
} @array;