在什么情况下mergesort比选择排序更快

时间:2016-06-20 07:13:21

标签: java algorithm sorting

根据RAM模型进行计算,得出使用选择排序可以更有效地排序并且使用mergesort排序效率更低的元素的数量非常低(n <500000)。但是,当我试图测试这个时,我发现选择排序在3分11秒内对500000个元素进行排序,并且合并在6分44秒内完成。我确信这两种算法的实现都是正确的。发生了什么?请解释。

抱歉,我编辑本文的时间已经很晚了。我丢失了网络连接。

所以这是我的mergesort:

public class MergeSort {

    // temp array
    public static int temp[];

    public static void merge(int a[], int low, int mid, int high)
    {
       temp = new int [a.length];
       for(int i = low; i <= high; i++)
           temp[i] = a[i];

       int i = low;
       int j = mid + 1;
       int k = low;

       while(i <= mid && j <= high)
       {
           if(temp[i] <= temp[j])
           {
               a[k] = temp[i];
               i++;
           }

           else
           {
               a[k] = temp[j];
               j++;
           }

           k++;
       }

       while(i <= mid)
       {
           a[k] = temp[i];
           k++;
           i++;
       }
    }

    public static void sort(int a[], int low, int high)
    {
        if(low < high)
        {
            int middle = (low + high) / 2;

            // sort the left half
            sort(a, low, middle);

            // sort the right half
            sort(a, middle + 1, high);

            // merge parts
            merge(a, low, middle, high);
        }
    }
}

和我的选择排序:

public static int[] selSort(int a[])
{
    int length = a.length;
    int temp[] = new int [length];

    System.arraycopy(a, 0, temp, 0, length);

    for(int i = 0; i < length - 1; i++)
    {
        int smIndex = i;

        for(int cIndex = i + 1; cIndex < length; ++cIndex)
            if(temp[cIndex] < temp[smIndex])
                smIndex = cIndex;

        int t = temp[smIndex];
        temp[smIndex] = temp[i];
        temp[i] = t;
    }

    return temp;
}

在选择排序中,我正在复制数组。

1 个答案:

答案 0 :(得分:1)

问题是merge()基于a.length分配temp [],当它应该只分配temp = new int [high + 1 - low]时。在此修复之后,对temp [i]的引用应更改为temp [i-low]。

使用当前代码,Java必须分配500,000个元素数组,即使它只合并1个偶数和1个奇数元素(高+ 1 - 低== 2)。

稍微优化的自顶向下合并排序的示例,它只分配一次临时缓冲区,然后使用相互递归的函数来避免复制。在此示例中,ee是结束索引== a.length。这将在不到十分之一秒的时间内对500,000个整数进行排序,在不到1.5秒的时间内对10,000,000个整数进行排序。

static void MergeSort(int a[]) {
    if (a.length < 2)
        return;
    int []b = new int[a.length];
    MergeSortAtoA(a, b, 0, a.length);
}

static void MergeSortAtoA(int a[], int b[], int ll, int ee)
{
    if (ee - ll > 1) {
        int rr = (ll + ee)>>1;          // midpoint, start of right half
        MergeSortAtoB(a, b, ll, rr);
        MergeSortAtoB(a, b, rr, ee);
        Merge(b, a, ll, rr, ee);        // merge b to a
    }
}

static void MergeSortAtoB(int a[], int b[], int ll, int ee)
{
    if (ee - ll > 1) {
        int rr = (ll + ee)>>1;          //midpoint, start of right half
        MergeSortAtoA(a, b, ll, rr);
        MergeSortAtoA(a, b, rr, ee);
        Merge(a, b, ll, rr, ee);        // merge a to b
    } else if ((ee - ll) == 1) {
        b[ll] = a[ll];
    }
}

static void Merge(int []a, int []b, int ll, int rr, int ee) {
    int o = ll;                         // b[]       index
    int l = ll;                         // a[] left  index
    int r = rr;                         // a[] right index
    while(true){                        // merge data
        if(a[l] <= a[r]){               // if a[l] <= a[r]
            b[o++] = a[l++];            //   copy a[l]
            if(l < rr)                  //   if not end of left run
                continue;               //     continue (back to while)
            while(r < ee){              //   else copy rest of right run
                b[o++] = a[r++];
            }
            break;                      //     and return
        } else {                        // else a[l] > a[r]
            b[o++] = a[r++];            //   copy a[r]
            if(r < ee)                  //   if not end of right run
                continue;               //     continue (back to while)
            while(l < rr){              //   else copy rest of left run
                b[o++] = a[l++];
            }
            break;                      //     and return
        }
    }
}