【问题标题】:How to understand abstract in-place merge sort如何理解抽象的就地合并排序
【发布时间】:2015-12-10 04:56:57
【问题描述】:

我无法理解合并排序。例如,为什么 var I 可以大于 var mid?这是不可能的,因为 3 个变量:lo 表示低,hi 表示高,mid 表示平均?

所以我看不到如果 i>mid 会发生什么。

public static void merge(Comparable[] a, int lo, int mid, int hi) {

int i = lo, j = mid + 1;
for (int k = 0; k <= hi; k++) {
    aux[k] = a[k];
}
for (int k = lo; k <= hi; k++) {
    if (i > mid) {
        a[k] = aux[j++];
    } else if (j > hi) {
        a[k] = aux[i++];
    } else if(less(aux[j],aux[i])){
        a[k] = aux[j++];
    } else {
        a[k] = aux[i++];
    }
    }
}

【问题讨论】:

    标签: sorting merge in-place


    【解决方案1】:

    就地合并排序的工作原理如下:如果您的数组为空或只有一个元素,则对其进行排序。如果它有两个元素,您可以通过适当的交换轻松对其进行排序。如果它有两个以上的元素,请执行以下操作:

    • 在中点将数组一分为二mid
    • 在左半边调用归并排序;
    • 在右半边调用归并排序;
    • 通过从两个子数组中挑选最小的头部元素来合并数组,直到它们被耗尽。

    您发布的代码不是完整的归并排序;它只是合并部分。此时您有两个已排序的子数组。需要复制两个子数组,以便您可以用排序值填充原始数组。

    在此实现中,子数组存储在一个连续数组中,aux

       lo         A         mid     B       hi
        +---+---+---+---+---++---+---+---+---+
        | 1 | 5 | 6 | 8 | 9 || 2 | 3 | 4 | 7 |
        +---+---+---+---+---++---+---+---+---+
        i ->                 j ->
    

    这里,iA 的索引,它从 0 到 mid(含)。 jB 的索引,它从mid+1hi 包含在内。循环的管理索引k 是合并操作的计数;每次迭代都有一个。

    所有整数值都是数组索引;它们不代表平均值等值。合并算法依赖于被排序的子数组。

    注释合并循环:

    for (int k = lo; k <= hi; k++) {
        if (i > mid) {                      // A is exhausted, ...
            a[k] = aux[j++];                // ..., take B[j]
        } else if (j > hi) {                // B is exhausted, ...
            a[k] = aux[i++];                // ..., take A[i]
        } else if(less(aux[j], aux[i])) {   // B[j] < A[i], ...
            a[k] = aux[j++];                // ..., take B[j]
        } else {                            // A[i] <= B[j], ...
            a[k] = aux[i++];                // ..., take A[i]
        }
    }
    

    这里,“take”的意思是“追加到合并数组并推进适当的数组计数器”。

    【讨论】:

    • 我知道了,但我想知道,当 var I 增加时,它会在 var mid 之前停止,所以 var I 永远不会大于 mid
    • 是的,这是真的。 aux[mid - 1]A 的最后一个元素,aux[mid]B 的第一个元素。
    • (在 C 中,通常用包含的下限和互斥的上限来描述一个范围。这与数组具有元素 0,但索引“n”是刚刚超出n 元素数组的限制。在我看来,将hi 作为数组的最后一个索引而不是除此之外的一个索引是一个糟糕的设计选择。如果hi 是唯一的上限,两个数组的界限只是[lo, mid)[mid, hi)。另外,我们不必在循环条件中编写统一的´
    • 不太熟悉 Java,但我认为索引的工作方式与 C 或 C++ 中的相同。但我明白你的意思:我上面的解释是一次性的:aux[mid]A 的最后一个元素,B 的第一个元素是aux[mid + 1]。所以midhigh 都是包含范围。对此感到抱歉。
    • 非常感谢,你让我了解了原地归并排序的真相,只有一个问题需要解决
    猜你喜欢
    • 2020-12-28
    • 1970-01-01
    • 2011-04-01
    • 2023-01-03
    • 1970-01-01
    • 2018-01-25
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    相关资源
    最近更新 更多