Java:实现合并排序

时间:2018-05-17 14:48:03

标签: java sorting mergesort

我想使用一个mergeSort方法实现Merge Sort,该方法将int数组的序列分开,直到它是单个元素并使用方法merge将它们放在一起。 使用我的代码,我得到一个Stackoverflow错误。 任何人都知道为什么?

public static int[] mergeSort(int[] seq) {
    return mergeSort(seq, 0, seq.length - 1);
}
private static int[] mergeSort(int[] seq, int l, int r) {

    if (seq.length < 2) {
        return seq;
    }
    int s = (l + r) / 2;
    int[] a = new int[s];
    int[] b = new int[seq.length - s];
    for (int i : a) {
        a[i] = seq[i];
    }
    for (int j : b) {
        b[j] = seq[s + j];
    }
    mergeSort(a);
    mergeSort(b);

    return merge(a, b);
}

public static int[] merge(int[] ls, int[] rs) {
    // Store the result in this array
    int[] result = new int[ls.length + rs.length];

    int i, l, r;
    i = l = r = 0;
    while (i < result.length) {
        if (l < ls.length && r < rs.length) {
            if (ls[l] < rs[r]) {
                result[i] = ls[l];
                ++i;
                ++l;
            } else {
                result[i] = rs[r];
                ++i;
                ++r;
            }
        } else if (l >= ls.length) {
            while (r < rs.length) {
                result[i] = rs[r];
                ++i;
                ++r;
            }
        } else if (r >= rs.length) {
            while (l < ls.length) {
                result[i] = ls[l];
                ++i;
                ++l;
            }
        }
    }
    return result;
}

2 个答案:

答案 0 :(得分:0)

堆栈溢出是通过递归调用方法太多次,可能是无限的。

private static int[] mergeSort(int[] seq, int l, int r)这将始终以l = 0和r = seq.length-1调用,因此不需要重载。

这里:int s = (l + r) / 2;如果数组有2个元素,这将返回0(l = 0,r = 1),因此数组将被分割为长度0和长度2(这里是什么导致无限递归调用)。在结果中添加一个,并且数组的拆分将正常工作。

要复制原始数组的部分,使用Arrays.copyOfRange()比编写自己的for循环更容易。而且您正在尝试使用数组ab的现有元素(全部为0)进行索引。

答案 1 :(得分:0)

您的代码存在两个小问题。

首先是:

public static int[] mergeSort(int[] seq) {
    return mergeSort(seq, 0, seq.length - 1);
}

您需要将其称为return mergeSort(seq, 0, seq.length);

背后的原因是,例如当你有2个元素并且你用-1来调用它时,你传递一个包含2个元素的数组,但s = 1 + 0/2 = 0并且你实际上并不是拆分它。每个后续的递归调用都使用一个空数组和一个具有相同2个元素的数组来完成,从而导致无限循环和堆栈溢出异常

第二个问题是这个问题:

  for (int i : a) {  and   for (int i : b) {

您不能执行for循环,因为您希望迭代索引而不是数组的值。您需要将其更改为:

   for (int i=0;i<a.length;i++) {
        a[i] = seq[i];
    }
    for (int i=0;i<b.length;i++) {
        b[i] = seq[s + i];
    }

您的代码的最后一个问题是您没有分配生成的排序数组的值,当您执行递归调用时,它会返回已排序的子部分,但您无法获得结果。它应该成为:

a=mergeSort(a);
b=mergeSort(b);

这是最终的代码:

public static void main(String... args) {
        int[] array={3,9,4,5,1} ;
        array=mergeSort(array);
        for(int i:array) {
            System.out.print(i+",");    
        }
    }


    private static int[] mergeSort(int[] seq) {

        if (seq.length < 2) {
            return seq;
        }
        int s = seq.length / 2; //You always use that value. no need for 2 methods
        int[] a = new int[s];
        int[] b = new int[seq.length - s];
        for (int i=0;i<a.length;i++) {
            a[i] = seq[i];
        }
        for (int i=0;i<b.length;i++) {
            b[i] = seq[s + i];
        }
        a=mergeSort(a);
        b=mergeSort(b);

        return merge(a, b);
    }

    public static int[] merge(int[] ls, int[] rs) {
        // Store the result in this array
        int[] result = new int[ls.length + rs.length];

        int i, l, r;
        i = l = r = 0;
        while (i < result.length) {
            if (l < ls.length && r < rs.length) {
                if (ls[l] < rs[r]) {
                    result[i] = ls[l];
                    ++i;
                    ++l;
                } else {
                    result[i] = rs[r];
                    ++i;
                    ++r;
                }
            } else if (l >= ls.length) {
                while (r < rs.length) {
                    result[i] = rs[r];
                    ++i;
                    ++r;
                }
            } else if (r >= rs.length) {
                while (l < ls.length) {
                    result[i] = ls[l];
                    ++i;
                    ++l;
                }
            }
        }
        return result;
    }