大多数排序算法都依赖于比较函数的正确实现,该函数返回两个元素之间的排序,也就是说,该函数接收两个元素并返回第一个元素是否小于、等于或大于第二个元素:
function compare(x, y) {
if (x < y) {
return LESS_THAN;
} else if (x > y) {
return GREATER_THAN;
} else {
return EQUAL;
}
}
比较函数需要对序列中的元素定义一个有效的总排序,以便使排序算法有任何意义。
人们很想问,使用随机比较函数是否能提供一种洗牌序列的聪明方法。简短的回答是否定的,通常来说。这样做真的不是一个好主意,即使它确实以某种方式神奇地发挥作用。正确的解决方案是使用Fisher-Yates洗牌算法。
从工程的角度来看,排序函数被设计用来对事物进行排序。滥用它来洗一个数组是自找麻烦,因为你永远不知道接下来的排序算法的变化是否会破坏 "洗牌 "算法。更糟糕的是,这种破坏可能是微妙的,在输出中产生的偏差可能很难被发现,除非测试严格地验证统计数据。此外,一些排序算法在使用随机比较器的情况下会运行得异常缓慢,或者在随机性对其不利的情况下需要很长的时间。
从数学的角度来看,有界时间的确定性比较排序就是不能给你一个高质量的随机排列组合的分布!事实上,如果你使用一个随机比较器,其返回LESS_THAN 或GREATER_THAN 的概率相同(一个 "均匀随机比较器"),可以证明这样的算法不可能正确洗牌。
假设你有一个大小为N 的数组。在一次完美的洗牌中,任何元素(例如第一个元素)结束在任何位置(例如最后一个位置)的概率总是1/N 。
在确定性比较排序算法的每一步,它都必须根据两个选定元素之间的排序做出某种二元决定,从而导致二元决策树。这些决策的结果决定了最终的排序输出。
现在,如果你给它一个均匀随机的比较器,所做的决定总是随机的。这意味着每个决定都有一个1/2 的概率去做一个或另一个。这就导致了决策树的路径p ,最终在n[p] 轮后终止,因为我们假设的是有界的时间。这个决策树中的某些路径将导致第一个元素最终出现在最后一个位置的情况。因此,这种情况的总体概率是导致所需情况的每条路径p 的概率之和:
∑[p ∈ all_desired_paths] (1/2)^(n[p])
将1/2 的幂相加,总会得到一个分母是2 的某个幂的分数。由于正确的概率是1/N ,除非N 也是2的幂,否则结果根本不可能是正确的。因此,在一般情况下,没有办法得到准确的概率1/N 。
编辑:Chris P.指出,该算法必须有约束的时间,这个证明才会有效。谢谢!