合并排序错误的输出

时间:2015-07-14 04:14:02

标签: java algorithm sorting debugging mergesort

我在Java中使用合并排序代码遇到两个问题。

  1. 当我输入数组[3,4,2,1,0,6,8]时,我得到输出[0,1,2,3,4,6,0] ,这显然是错误的。

  2. 我怀疑我编写代码的方式不尽如人意。如果您能找到任何改进,请告诉我。我知道网上已有大量的mergesort算法,但我要具体询问我编写代码的方式。谢谢!

    import java.util.Arrays;
    
    public class Main {
    
        static int[] mergeSort(int[] arr) {
    
            if (arr == null)
                return null;
    
            if (arr.length <= 1)
                return arr;
    
            int length = arr.length;
            int mid = arr.length / 2;
    
            int[] left = Arrays.copyOfRange(arr, 0, mid);
            int[] right = Arrays.copyOfRange(arr, mid, length);
    
            int[] sortedLeft = mergeSort(left);
            int[] sortedRight = mergeSort(right);
    
            int leftSmallestIndex = 0;
            int rightSmallestIndex = 0;
    
            int leftLength = left.length;
            int rightLength = right.length;
    
            int[] sortedArr = new int[length];
    
            outer: for (int i = 0; i < length; i++) {
                if (leftSmallestIndex >= leftLength) {
                    while (rightSmallestIndex < rightLength) {
                        sortedArr[i] = sortedRight[rightSmallestIndex];
                        rightSmallestIndex++;
                        break outer;
                    }
                }
                if (rightSmallestIndex >= rightLength) {
                    while (leftSmallestIndex < leftLength) {
                        sortedArr[i] = sortedLeft[leftSmallestIndex];
                        leftSmallestIndex++;
                        break outer;
                    }
                }
                if (sortedLeft[leftSmallestIndex] < sortedRight[rightSmallestIndex]) {
                    sortedArr[i] = sortedLeft[leftSmallestIndex];
                    leftSmallestIndex++;
                }
                else {
                    sortedArr[i] = sortedRight[rightSmallestIndex];
                    rightSmallestIndex++;
                }
            }
    
            return sortedArr;
    
        }
    
        public static void main(String[] args) {
        // write your code here
            int[] a = new int[] {3,4,2,1,0,6,8};
            System.out.println(Arrays.toString(mergeSort(a)));
        }
    }
    

2 个答案:

答案 0 :(得分:3)

你的语句break outer;实际上导致控件退出for循环,它不会继续for循环(我猜你正试图继续使用for循环,使用break outer;声明)。

这会导致循环仅更新sortedRightsortedLeft中的一个剩余元素以进入已排序的数组而其他元素被遗漏,这导致0结束时你的循环。

你实际上不需要这样做,你可以循环直到 - leftSmallestIndex < leftLength && rightSmallestIndex < rightLength,然后在for循环中定义你在for循环中定义的while循环。

示例 -

import java.util.*;
import java.math.*;
class a {
    static int[] mergeSort(int[] arr) {

        if (arr == null)
            return null;

        if (arr.length <= 1)
            return arr;

        int length = arr.length;
        int mid = length / 2;

        int[] left = Arrays.copyOfRange(arr, 0, mid);
        int[] right = Arrays.copyOfRange(arr, mid, length);

        int[] sortedLeft = mergeSort(left);
        int[] sortedRight = mergeSort(right);

        int leftSmallestIndex = 0;
        int rightSmallestIndex = 0;

        int leftLength = left.length;
        int rightLength = right.length;

        int[] sortedArr = new int[length];
        int i = 0;
        for (; leftSmallestIndex < leftLength && rightSmallestIndex < rightLength;i++) {
            if (sortedLeft[leftSmallestIndex] < sortedRight[rightSmallestIndex]) {
                sortedArr[i] = sortedLeft[leftSmallestIndex];
                leftSmallestIndex++;
            }
            else {
                sortedArr[i] = sortedRight[rightSmallestIndex];
                rightSmallestIndex++;
            }
        }
        while (rightSmallestIndex < rightLength) {
            sortedArr[i] = sortedRight[rightSmallestIndex];
            rightSmallestIndex++;
            i++;
        }
        while (leftSmallestIndex < leftLength) {
           sortedArr[i] = sortedLeft[leftSmallestIndex];
           leftSmallestIndex++;
           i++;
        }
        return sortedArr;

    }
    public static void main(String[] args) {
     int[] a = new int[] {3,4,2,1,0,6,8};
        System.out.println(Arrays.toString(mergeSort(a)));
        outer : for(int i = 0;i < 10 ; i++) {
        while(true) {
            System.out.println(i);
            break outer;
        }
    }
    }
}

最后,我添加了示例(使用break outer;尝试的简单版本,它应该可以帮助您了解发生了什么)。

答案 1 :(得分:2)

您的问题出在while循环中:

while (rightSmallestIndex < rightLength) {
                sortedArr[i] = sortedRight[rightSmallestIndex];
                rightSmallestIndex++;
                break outer;
            }

永远不会循环,因为你的break语句是INSIDE while。此外,你不会在while内部增加i,所以即使它循环,它也会覆盖当前索引处的值而不是填充数组的其余部分

将它们更改为

       if (leftSmallestIndex >= leftLength) {
            while (rightSmallestIndex < rightLength) {
                sortedArr[i] = sortedRight[rightSmallestIndex];
                rightSmallestIndex++;
                i++;
            }
                break outer;

        }
        if (rightSmallestIndex >= rightLength) {
            while (leftSmallestIndex < leftLength) {
                sortedArr[i] = sortedLeft[leftSmallestIndex];
                i++;
                leftSmallestIndex++;
            }
                break outer;

        }
      ..rest is the same

应该给你正确的结果

至于改进......

  1. 不要使用标签和break LABEL声明,它会让人感到非常困惑。可能更清楚的是将这些部分重构为他们自己的方法,意图揭示方法名称,如fillInRemainingArray()

  2. 我认为你不需要复制数组,你应该能够只用1个数组合并