额外的存储合并排序

时间:2010-05-18 21:01:49

标签: java algorithm

我需要使用额外的数组进行合并排序。这是我的代码:

public class extra_storage{  
    public static void main(String[]args) { 

        int x[]=new int[]{12,9,4,99,120,1,3,10};
        int a[]=new int[x.length];

        mergesort(x,0,x.length-1,a);
        for (int i=0;i<x.length;i++){
            System.out.println(x[i]);
        }       
    }

    public static void mergesort(int x[],int low,int high, int a[]){      
        if (low>=high) {
            return;
        }
        int middle=(low+high)/2;
        mergesort(x,low,middle,a);
        mergesort(x,middle+1,high,a);
        int k;
        int lo=low;
        int h=high;
        for (k=low;k<high;k++)
            if ((lo<=middle ) && ((h>high)||(x[lo]<x[h]))){
                a[k]=x[lo++];
            }
            else {
                a[k]=x[h++];
            }
        for (k=low;k<=high;k++){
            x[k]=a[k];
        }     
    }
}

但是出了点问题。当我运行它时输出是这样的:

1
0
3
0
4
0
9
0

有什么问题?

3 个答案:

答案 0 :(得分:2)

这是您的原始算法,其中包含一些更正和风格改进:

public class MergeSort {  
    public static void main(String[]args) { 
        int[] nums = {12,9,4,99,120,1,3,10};
        mergeSort(nums);
        System.out.println(java.util.Arrays.toString(nums));
        // "[1, 3, 4, 9, 10, 12, 99, 120]"
    }
    static void mergeSort(int[] arr) {
        mergeSort(arr, 0, arr.length - 1, new int[arr.length]);
    }
    static void mergeSort(int[] arr, int low, int high, int[] buff){
        if (low >= high) {
            return;
        }
        int mid = (low + high) >>> 1;
        mergeSort(arr, low, mid, buff);
        mergeSort(arr, mid+1, high, buff);
        for (int left = low, right = mid + 1, i = low; i <= high; i++) {
            if (right > high || left <= mid && arr[left] <= arr[right]) {
                buff[i] = arr[left++];
            } else {
                buff[i] = arr[right++];
            }
        }
        for (int i = low; i <= high; i++) {
            arr[i] = buff[i];
        }
    }
}

与Eyal的实现不同,srcdst的角色在递归级别之间来回交换,这里我们总是排序到相同的数组对象arr,并且数组对象buff始终仅用作合并的临时缓冲区(因此,在合并阶段之后存在复制阶段)。这仍然是O(N log N),但Eyal更高级的实施将是一个不变因素的改进。

在合并循环

基本上,左子阵列有left索引,右子阵列有right索引,你可以从leftright中选择正确的元素放入buff

有效的元素范围是(包含边界):

    左侧子阵列
  • left = low...mid
  • right = mid+1...high用于右子阵列

要评估要选择的元素,请考虑选择left元素的条件。它发生在:

  • 没有更多元素可以从右侧子阵列中选择(即right > high
  • OR (有条件地)还有一个要从左侧子阵列中挑选的元素(即left <= mid)和(有条件地)该元素小于或等于来自右子阵列的元素(即arr[left] <= arr[right])。

在此处使用短路条件和&&JLS 15.23)和条件 - 或||JLS 15.24)运算符非常重要,并相应地对这些条件进行排序。否则你会得到ArrayIndexOutOfBoundsException

相关问题


找到两个数字之间的平均值

通常会看到以下内容:

int mid = (low + high) / 2; // BROKEN! Can result in negative!

问题是,现在,数组/列表等很容易超过2个 30 元素,上面会导致溢出并导致负数。

Josh Bloch倡导的新成语如下:

int mid = (low + high) >>> 1; // WORKS PERFECTLY!

这使用无符号右移运算符(JLS 15.19);它根据我们的需要正确处理添加的任何溢出。

参考

相关问题


关于数组声明

不要养成这样声明数组的习惯:

int x[];

您应该使用类型而不是标识符放置括号:

int[] x;

相关问题

答案 1 :(得分:1)

您似乎有堆栈溢出。

在您的代码中

public static void mergesort(int x[],int low,int high, int a[]){      
    if (low>high) {
        return;
    }
    int middle=(low+high)/2;
    mergesort(x,low,middle,a);
    mergesort(x,middle+1,high,a);

如果低开始低或高等于高,那么它将最终等于高,在这种情况下,中间==低==高,它将自动调用自身。


问题被更改为在提交答案后删除堆栈溢出。

答案 2 :(得分:1)

您的代码不够清晰,并且有许多不相关的操作。此外,它没有表现出您描述的行为。

您尝试实现的mergesort版本的想法是使用与输入数组相同大小的单个辅助数组(源数组)(目标数组 )。这允许从一个阵列合并到另一个阵列,因为没有有效的就地合并技术。该算法包括将目标数组的两半分类到源数组中的相应范围,然后将两半合并回目标数组。请注意,这要求在每次调用时,两个数组在由low和high指定的范围内是相同的。

以下是int数组的实现。您可以添加优化,例如对小输入执行插入排序,或者在可能的情况下附加一半而不是合并它们。这种优化可以在Arrays.sort(Object[])的实现中找到。

public static void mergeSort(int[] arr){
    int[] aux = arr.clone();
    mergeSort(aux, 0, arr.length, arr);
}

private static void mergeSort(int[] src, int low,  int high, int[] dst) {
    // One or no items - nothing to sort  
    if (high-low<=1)
        return;

    // Recursively sorting into src
    int mid = (low + high) / 2;
    mergeSort(dst, low, mid, src);
    mergeSort(dst, mid, high, src);

    // Merge halves into dst
    for(int i = low, p = low, q = mid; i < high; i++) {
        if (q >= high || p < mid && src[p] <= src[q])
            dst[i] = src[p++];
        else
            dst[i] = src[q++];
    }
}