我做了一个基于比较的mergesort算法分析,它按升序输出。当我给它一个反向排序列表而不是升序排序列表时,我注意到它更快(具有更少的比较)。任何人都可以解释原因吗?
答案 0 :(得分:2)
排序代码中一定有错误。
根据我的理解,文字MergeSort执行的比较次数应该是独立的数据。这意味着它不能比O(n log n)
差,但也不会更好(除非你做一些聪明的修改,比如“自然合并”或TimSort)。
答案 1 :(得分:2)
要合并两个长度为M和N的列表,您最多需要M + N-1个比较。如果第一个列表中的所有条目都小于第二个列表中的条目,则只需要进行M次比较。如果第二个列表中的所有条目都小于第一个列表中的条目,则只需要进行N次比较。
如果您要排序的数字总数不是2的效力,那么您将有两个不同长度的列表。我怀疑你实现了merge-sort,这两种方法中的第一个有一个元素。这意味着该分区和合并的M = N + 1。如果您的元素的顺序相反,则第二个列表中的所有元素都将小于第一个列表中的元素,如果顺序正确,则需要进行N次比较而不是M.
如果要排序的列表的效力为2,则正常顺序和反向顺序之间应该没有区别。
答案 2 :(得分:0)
使用自上而下的归并排序实现,升序排序列表不会经过下面代码中的 merge() 步骤。因此,它是最快的。此外,反向排序列表会跳过 merge() 步骤中比较步骤的某些部分。例如,它不会进入我代码中下面的比较行。
else if (comp(aux[j], aux[i])) a[k] = aux[j++]; // B[j] < A[i], take B[je
因此,它也比遍历所有代码的随机排序列表更快。
供您参考:
void merge(int *a, int *aux, int lo, int mi, int hi, bool (*comp)(int, int)) {
assert(sorted(a, lo, mi, comp)); // precondition: a[lo..mi] sorted
assert(sorted(a, mi+1, hi, comp)); // precondition: a[mi+1..hi] sorted
for (int k = lo; k <= hi; k++) aux[k] = a[k];
int i = lo;
int j = mi + 1;
for (int k = lo; k <= hi; k++) {
if (i > mi) a[k] = aux[j++]; // A is exhausted, take B[j]
else if (j > hi) a[k] = aux[i++]; // B is exhausted, take A[i]
else if (comp(aux[j], aux[i])) a[k] = aux[j++]; // B[j] < A[i], take B[j]
else a[k] = aux[i++]; // A[i] <= B[j], take A[i]
}
assert(sorted(a, lo, hi, comp)); // postcondition: a[lo..hi] sorted
}
void mergesort(int *a, int *aux, int lo, int hi, bool (*comp)(int, int)) {
if (hi <= lo) return;
int mi = lo + (hi - lo) / 2;
mergesort(a, aux, lo, mi, comp);
mergesort(a, aux, mi + 1, hi, comp);
if (comp(a[mi], a[mi + 1])) return; // already sorted
merge(a, aux, lo, mi, hi, comp);
}
(债务人)<><