简体   繁体   English

Java:实现合并排序

[英]Java: Implementing Merge Sort

I want to implement Merge Sort using one a mergeSort method that splits the sequences of an int array up until it's a single element and using a method merge to put them together. 我想使用一个mergeSort方法来实现合并排序,该方法将int数组的序列拆分为单个元素,然后使用方法合并将它们放在一起。 With my code as it is I get a Stackoverflow Error. 与我的代码一样,我得到一个Stackoverflow错误。 Anyone has an idea why? 有人知道为什么吗?

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;
}

The stack overflow is caused by calling the method recursively too many times, possibly infinitely. 堆栈溢出是由递归调用该方法的次数过多(可能是无限次)引起的。

private static int[] mergeSort(int[] seq, int l, int r) this will always be called with l=0 and r=seq.length-1, so it's not really necessary to overload. private static int[] mergeSort(int[] seq, int l, int r)始终使用l = 0和r = seq.length-1进行调用,因此实际上并不需要重载。

Here: int s = (l + r) / 2; 此处: int s = (l + r) / 2; if the array has 2 elements, this will return 0 (l=0, r=1), so the array will be split to a length 0, and a length 2 (and here is what causes the infinite recursive calls). 如果数组有2个元素,则将返回0(l = 0,r = 1),因此数组将被拆分为长度0和长度2(这是导致无限递归调用的原因)。 Add one to the result, and the splitting of the array will work correctly. 将一个加到结果中,数组的分割将正常工作。

To copy the parts of the original array, it's easier to use Arrays.copyOfRange() than writing your own for loop. 要复制原始数组的各个部分,使用Arrays.copyOfRange()比编写自己的for循环要容易得多。 And you're trying to use the existing elements of arrays a and b , which will all be 0, for indexing. 并且您尝试使用数组ab的现有元素(全部为0)进行索引。

There are two small issues with your code. 您的代码有两个小问题。

First one is here: 第一个在这里:

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

You need to call it as return mergeSort(seq, 0, seq.length); 您需要将其称为return mergeSort(seq, 0, seq.length);

The reason behind that is that for example when you have 2 elements and you call it like that with -1 you pass an array with 2 elements but s=1+0/2 =0 and you don't actually split it. 这背后的原因是,例如,当您有2个元素并且用-1调用它时,您传递了一个包含2个元素但s = 1 + 0/2 = 0的数组,而实际上并未拆分它。 Each subsequent recursion call is done with one empty array and one array with the same 2 elements causing an infinite loop and a stackoverflow exception 随后的每个递归调用都使用一个空数组和一个具有相同2个元素的数组完成,从而导致无限循环和stackoverflow异常

The second problem is this one: 第二个问题是这个:

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

You can't do the for loop like because you want to iterate on indexes not values of the array. 您无法执行for循环,因为您要迭代索引而不是数组的值。 You need to change it to: 您需要将其更改为:

   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];
    }

And the last problem with your code is that you don't assign the values of the resulting sorted array and when you do the recursive calls it returns the sorted sub part but you don't get the result. 代码的最后一个问题是,您不分配结果排序数组的值,并且当您进行递归调用时,它会返回排序后的子部分,但不会得到结果。 It should become: 它应该变成:

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

And here is the final code: 这是最终代码:

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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM