【问题标题】:Implementing merge sort in Java: Only zeroes在 Java 中实现归并排序:只有零
【发布时间】:2017-01-06 13:07:22
【问题描述】:

我正在尝试在 Java 中实现一些排序算法,将 int-arrays 作为一个教育过程。我目前试图围绕合并排序。昨天我走了很远,结果数组大小正确,但只包含零。今天我从头开始,现在我被困在同一点上。 ^^ 这是我的代码:

public static int[] mergeSort(int[] array) {
    if (array.length < 2) {
        return array;
    }
    int left = 0;
    int right = array.length;
    int p = array.length / 2;
    int[] lArray = Arrays.copyOfRange(array, left, p);
    int[] rArray = Arrays.copyOfRange(array, p, right);
    lArray = mergeSort(lArray);
    rArray = mergeSort(rArray);
    return merge(lArray, rArray);
}

private static int[] merge(int[] lArray, int[] rArray) {
    int[] result = new int[lArray.length + rArray.length];
    int idx = 0;
    int rIdx = 0;
    int lIdx = 0;
    while (lIdx < lArray.length - 1 && rIdx < rArray.length - 1) {
        if (lArray[lIdx] < rArray[rIdx]) {
            result[idx] = lArray[lIdx];
            lIdx++;
        } else if (lArray[lIdx] >= rArray[rIdx]) {
            result[idx] = rArray[rIdx];
            rIdx++;
        }
        idx++;
    }
    if (lIdx < (lArray.length - 1)) {
        result[idx] = lArray[lIdx + 1];
    } else if (rIdx < (rArray.length - 1)) {
        result[idx] = rArray[rIdx + 1];
    }
    return result;
}

我认为它的风格和可读性都很好。所以,你所有的算法和 Java 破解在那里,我错过了什么?调试指向合并方法,但我不能完全确定,所以我按原样发布。

提前致谢!

【问题讨论】:

  • 您是否只是尝试使用一个短数组逐步调试此操作以查找零的来源?调试器是你最好的朋友
  • 你不能考虑使用变量名像lIdxrIdxp这样可读的东西
  • 我一直在尝试完全按照您的建议进行调试 - 正如我所说,我看到提示我在合并方法错误,但我不确定具体在哪里。哦,你对一个变量名 p 是正确的。我坚持使用教授提供的伪代码,却忘了对此发表评论。然而,我发现过长的语句比明显的缩写更影响可读性。 :)

标签: java algorithm sorting mergesort


【解决方案1】:

我在您的 merge 方法中发现了两个问题:

首先,您的 while 循环会忽略左右数组的最后一个元素。你应该改变

while (lIdx < lArray.length - 1 && rIdx < rArray.length - 1)

while (lIdx < lArray.length && rIdx < rArray.length)

其次,在那个while循环之后,你还需要两个while循环来添加左数组的尾部或右数组的尾部。相反,您只添加一个元素。

替换

if (lIdx < (lArray.length - 1)) {
    result[idx] = lArray[lIdx + 1];
} else if (rIdx < (rArray.length - 1)) {
    result[idx] = rArray[rIdx + 1];
}

while (lIdx < lArray.length) {
    result[idx++] = lArray[lIdx++];
} 
while (rIdx < rArray.length) {
    result[idx++] = rArray[rIdx++];
}

【讨论】:

  • 第二次添加 idx++ 所以:result[idx++] = rArray[rIdx++];结果[idx++] = lArray[lIdx++];
  • @RaulGuiu 谢谢。错过了
  • 为什么是第二个while循环?长度差只能是一个,由调用方法的逻辑决定。如果merge 是公开的,我同意,人们可能会想用任意长度的数组来调用它,但它是私有的。但是,是的,我忽略了两个数组中的最后一个元素。 m(谢谢,我会尽快检查您的修复(并最终将您的回复标记为正确)。
  • @Aarkon 这与长度差异无关。例如,假设 rArray 的所有元素都小于 lArray 的所有元素。第一个循环会将 rArray 的所有元素复制到合并后的数组中,并在 rIdx 达到 rArray.length 时终止。此时你必须遍历 lArray 的所有元素并将它们添加到合并的数组中。
  • 你是对的!这是我的错误。谢谢你和其他人! :)
【解决方案2】:
if (lIdx < (lArray.length - 1)) {
    result[idx] = lArray[lIdx + 1];
} else if (rIdx < (rArray.length - 1)) {
    result[idx] = rArray[rIdx + 1];
}

这部分有点奇怪。为什么只将剩余的一个元素复制到结果数组中?您应该将 lArray 或 rArray 中的所有剩余元素复制到结果中。使用 'while' 而不是 'if'。

【讨论】:

  • 这部分只是为了在上面的while语句已经遍历整个部分数组并且一个比另一个长之后进行清理。长度差只能是调用方法的逻辑一个。
【解决方案3】:

给你

public class MergeSort {

public static int[] mergeSort(int[] array) {
    if (array.length < 2) {
        return array;
    }
    int left = 0;
    int right = array.length;
    int p = array.length / 2;
    int[] lArray = Arrays.copyOfRange(array, left, p);
    int[] rArray = Arrays.copyOfRange(array, p, right);
    //printArray(lArray); seems ok
    //printArray(rArray); seems ok
    lArray = mergeSort(lArray);
    rArray = mergeSort(rArray);
    return merge(lArray, rArray);
}

private static int[] merge(int[] lArray, int[] rArray) {
    /*System.out.println("Ive got");
    printArray(lArray);
    printArray(rArray); seems ok*/
    int[] result = new int[lArray.length + rArray.length];
    int index = 0;
    int rightIndex = 0;
    int leftIndex = 0;
    while (leftIndex < lArray.length && rightIndex < rArray.length) { //TODO
        if (lArray[leftIndex] < rArray[rightIndex]) {
            result[index] = lArray[leftIndex];

            leftIndex++;
            index++;
            //} else if (lArray[leftIndex] >= rArray[rightIndex]) { // You don't have to check it!!!
        } else {
            System.out.println("2 left index " + leftIndex + " index " + index);
            result[index] = rArray[rightIndex];
            rightIndex++;
            index++;
        }
    }
    while (leftIndex < (lArray.length)) { // TODO
        result[index] = lArray[leftIndex];
        index++;
        leftIndex++;
    }
    while (rightIndex < (rArray.length)) { // TODO
        result[index] = rArray[rightIndex];
        index++;
        rightIndex++;
    }
    System.out.println("Returning ");
    printArray(result);
    return result;
}

public static void printArray(int[] arr) {
    for (int i : arr)
        System.out.print(i + " ");
    System.out.println();
}

public static void main(String[] args) {
    int[] arr = {2, 1, 3, 4, 0, -1};
    printArray(arr);
    arr = mergeSort(arr);
    printArray(arr);
}
}

出了什么问题用//TODO标记

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-11
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 2015-03-24
    • 1970-01-01
    相关资源
    最近更新 更多