我对http://algs4.cs.princeton.edu/23quicksort/Quick3way.java.html中quickSort的3路分区感兴趣 因为它使用该分区来克服就地快速排序中的荷兰国旗问题(相同的数据)。 由于作者是Sedgewick,我认为该代码中没有错误,但所选择的数据集最容易出现排序数据的时间复杂度。
根据维基百科:
在quicksort的早期版本中,通常会选择分区最左边的元素作为pivot元素。不幸的是,这会导致已经排序的数组的最坏情况行为,这是一个相当常见的用例。通过选择枢轴的随机索引,选择分区的中间索引或(特别是对于较长的分区)选择分区的第一个,中间和最后一个元素的中位数(如建议的那样),可以轻松解决问题。塞奇威克)。[17]
快速排序的代码:
// quicksort the subarray a[lo .. hi] using 3-way partitioning
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
int lt = lo, gt = hi;
Comparable v = a[lo];
int i = lo;
while (i <= gt) {
int cmp = a[i].compareTo(v);
if (cmp < 0) exch(a, lt++, i++);
else if (cmp > 0) exch(a, i, gt--);
else i++;
}
// a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi].
sort(a, lo, lt-1);
sort(a, gt+1, hi);
assert isSorted(a, lo, hi);
}
我是否正确使用mid或ninther作为枢轴或我错过了什么?我意识到这是教学但为什么不至少使用mid?
修改
洗牌是否被认为是一种严格的方法来防止最坏情况而不仅仅是选择更好的支点?为什么不只是改变枢轴......如果没有那么大量的随机性改组大数组会花费一些开销呢?由于shuffle算法需要额外的时间,为什么不选择枢轴?例如,用所有等效数据混洗数据是完全浪费的。在阵列上运行isSorted作为一种需要编辑等值数据的启发式是不是更好? - 没有人可以与Hoare争论,但是检查ifSorted是否会修改等效数据会导致短路而不是不必要地运行数据?这将需要同时洗牌。
答案 0 :(得分:1)
您引用的sort
方法是private
辅助方法。真正的public
方法sort
是这样的:
public static void sort(Comparable[] a) {
StdRandom.shuffle(a);
sort(a, 0, a.length - 1);
assert isSorted(a);
}
通过调用StdRandom.shuffle
,在执行quicksort之前,数组会随机混乱。这是防止最坏情况的方法。
它不仅用于这个3向分区快速排序,它也用于普通的快速排序。
引自Sedgewick的算法一书,§2.3QUICKSORT
Q值。随机改组数组似乎占用了排序总时间的很大一部分。这样做真的值得吗?
一个。是。它可以防止最坏的情况,并使运行时间可预测。 Hoare在1960年提出这种算法时提出了这种方法 - 它是一种典型的(并且是第一种)随机算法。