合并排序的另一种变体

时间:2015-12-11 11:44:20

标签: java algorithm sorting recursion mergesort

我应该使用更有效的合并排序变体,避免在使用两个相互递归的方法时递归分配数组。然而,由于其运行时间比通常的慢,因此这个不会变得更有效。任何建议将不胜感激

public static void main(String[] args) {
    int[] array = {38, 27, 43, 3, 9, 82};
    System.out.println("begin with: \n" + Arrays.toString(array));
    System.out.println("------------------");

    mergesort1(array, array.length);

    System.out.println("------------------");
    System.out.println("end with: \n" + Arrays.toString(array));
}

public static void mergesort1(int[] a, int last) {

    if (last > 1) {
        int l = (last / 2);
        int r = last - l;
        int[] leftArray = new int[l];
        int[] rightArray = new int[r];

        for (int i = 0; i < l; i++) {
            leftArray[i] = a[i];
        }
        for (int i = l; i < l + r; i++) {
            rightArray[i - l] = a[i];
        }
        mergesort1(rightArray, r);
        System.arraycopy(rightArray, 0, a, l, r);
        int[] t = new int[l];
        mergesort2(leftArray, l, t);
        System.arraycopy(t, 0, a, 0, l);
        merge(t, l, last, a);
        t = null;
    }
}

public static void mergesort2(int[] b, int last, int[] d) {
    if (last > 1) {
        int l = (last / 2);
        int r = last - l;
        int[] leftArray = new int[l];
        int[] rightArray = new int[r];
        int[] dArray = new int[r];
        System.arraycopy(b, 0, leftArray, 0, l);
        System.arraycopy(b, l, rightArray, 0, r);
        System.arraycopy(d, l, dArray, 0, r);
        mergesort1(leftArray, l);
        System.arraycopy(leftArray, 0, b, 0, l);
        mergesort2(rightArray, r, dArray);
        System.arraycopy(rightArray, 0, b, l, r);
        System.arraycopy(dArray, 0, d, l, r);
        merge(b, l, last, d);
    } else {
        d[0] = b[0]; // Trivial case
    }
}

public static void merge(int[] le, int l, int n, int[] a) {
    int i = 0;
    int j = l;
    int k = 0;
    int myTemp = 0;

    while ((i < l)) {
        if ((le[i] <= a[j]) || (a[j] == 0)) {
            if ((k < a.length)) {
                a[k] = le[i];
                i++;
            }
        } else {
            if ((k < a.length)) {
                int innerTemp = 0;
                if (myTemp == 0) {
                    a[k] = a[j];
                    innerTemp = 1;
                }
                j++;
                if (j == n) {
                    j--;
                    myTemp = 1;
                    if (innerTemp == 0) {
                        a[k] = le[i];
                        i++;
                    }
                }
            }
        }
        if ((k < a.length)) {
            k++;
        }
    }
}

*更新 我必须根据下面的建议尝试更新代码,但仍然没有给出正确的结果。

public static void main(String[] args) {
    int[] array = {38, 27, 43, 3, 9, 82};
    System.out.println("begin with: \n" + Arrays.toString(array));
    System.out.println("------------------");

    mergesort(array, array.length);

    System.out.println("------------------");
    System.out.println("end with: \n" + Arrays.toString(array));
}

public static void mergesort(int[] a, int size) {   
    if (size < 2) {
        return;
    }
    int[] b = new int[size];         
    mergesort1(a, b, 0, size-1);    

}

public static void mergesort1(int[] a, int[] b, int low, int end) {

    if ((end - low) == 1) 
    {
        return;                      
    }
    int mid = (low + end) / 2;
    mergesort1(a, b, low, mid);
    mergesort2(a, b, mid, end);       
    merge(b, a, low, mid, end);
}

public static void mergesort2(int[] a, int[] b, int low, int end) {
    if ((end - low) == 1) {            
        b[low] = a[low];             
        return;                      
    }
    int mid = (low + end) / 2;        
    mergesort1(a, b, low, mid);
    mergesort2(a, b, mid, end);       
    merge(a, b, low, mid, end);
}

public static void mergeArrays(int[] toSort, int[] tempArray, int low, int mid, int high) {
    int i = 0;
    int j = mid;
    int k = 0;
    int myTemp = 0;

    while ((i < mid)) {
        if ((tempArray[i] <= toSort[j]) || (toSort[j] == 0)) {
            if ((k < toSort.length)) {
                toSort[k] = tempArray[i];
                i++;
            }
        } else {
            if ((k < toSort.length)) {
                int innerTemp = 0;
                if (myTemp == 0) {
                    toSort[k] = toSort[j];
                    innerTemp = 1;
                }
                j++;
                if (j == high) {
                    j--;
                    myTemp = 1;
                    if (innerTemp == 0) {
                        toSort[k] = tempArray[i];
                        i++;
                    }
                }
            }
        }
        if ((k < toSort.length)) {
            k++;
        }
    }
}

3 个答案:

答案 0 :(得分:2)

您正在使用大量不必要的System.arraycopy。您只需在合并后使用一次数组副本,即可将合并后的数组复制到原始数组中。要将子数组传递给内部函数,您只需传递子数组的开始和结束索引。没有必要将它们复制到另一个数组中并将它们传递给函数。

答案 1 :(得分:1)

为了避免递归分配,请在main()或调用其中一个相互递归函数的入口函数中进行一次临时缓冲区分配。相互递归函数只生成索引并消除了复制的需要,而merge()执行实际的合并。此部分示例使用半闭区间,第一个(低)和结束参数。

void mergesort(int[] a, int size){   // entry function
    if(size < 2)
        return;
    int[] b = new int[size];         // allocate temp buffer just once
    mergesortatoa(a, b, 0, size);    // sort a
    delete[] b;                      // delete b
}

// merge sort from a to a
void mergesortatoa(int[] a, int[] b, int low, int end)
{
    if((end - low) == 1)             // if just 1 element
        return;                      //   return
    int mid = (low + end)/2          // or low + (end - low)/2
    mergesortatob(a, b, low, mid);
    mergesortatob(a, b, mid, end);
    merge(b, a, low, mid, end);
}

// merge sort from a to b
void mergesortatob(int[] a, int[] b, int low, int end)
{
    if((end - low) == 1){            // if just 1 element
        b[low] = a[low];             //   "mergesort" a to b
        return;                      //   return
    }
    int mid = (low + end)/2          // or low + (end - low)/2
    mergesortatoa(a, b, low, mid);
    mergesortatoa(a, b, mid, end);
    merge(a, b, low, mid, end);
}

// merge from x to y (no copy, just y[...] = x[...])
void merge(int[] x, int[] y, int low, int mid, int end)
{
    // ...
}

答案 2 :(得分:0)

您可以通过分配与原始数据大小相同的单个数组来避免许多副本,并且可以选择性地将合并执行到另一个数组。

当您进入微小的子阵列时,递归深度的奇偶校验将告诉您是否需要就地合并或与其他阵列合并。

38, 27, 43,  3,  9, 82
 -   -   -   -   -   -
====================== (in-place 0-1 and 3-4)
27, 38, 43,  3,  9, 82
 -   -   -   -   -   -
====================== (to copy, 0-2 and 3-5)
 -   -   -   -   -   -
27, 38, 43,  3,  9, 82
====================== (to original, 0-5)
 3,  9, 27, 38, 43, 82
 -   -   -   -   -   -