📜  如何使Mergesort在最佳情况下执行O(n)比较?

📅  最后修改于: 2021-05-04 16:26:25             🧑  作者: Mango

众所周知,Mergesort是一种分而治之的算法,它将数组递归地分成两半,直到达到大小为1的数组为止,然后合并排序后的子数组,直到对原始数组进行完全排序为止。在所有三种情况下(最佳,平均和最差),合并排序的典型实现都在O(n Log n)时间中进行。

我们需要将最佳情况下的性能从O(n log n)降低到O(n)。

想法是考虑数组已经排序的情况。合并之前,只需检查arr [mid]> arr [mid + 1],因为我们正在处理排序的子数组。这将导致我们得到递归关系T(n)= 2 * T(n / 2)+1,可以通过母定理来求解,因此T(n)= n。

例子:

Input : 1 2 3 4
Subarrays with size of 1:|1||2| |3||4|
Subarrays with size of 2: |1 2| |3 4|
Output : 1 2 3 4

Input : 1 2 3 4 5 6 7 8 
        Subarrays with size of 1: |1||2| |3||4| |5||6| |7||8|
        Subarrays with size of 2: |1 2| |3 4| |5 6| |7 8|
        Subarrays with size of 4: |1 2 3 4| |5 6 7 8|
Output : 1 2 3 4 5 6 7 8 
// C program to implement merge sort that works
// in O(n) time in best case.
#include 
#include 
  
void merge(int* arr, int low, int mid, int high);
  
void mergesort(int* arr, int low, int high)
{
    if (low < high) {
        int mid = (low + high) / 2;
        mergesort(arr, low, mid);
        mergesort(arr, mid + 1, high);
  
        // This is where we optimize for best
        // case.
        if (arr[mid] > arr[mid + 1])
            merge(arr, low, mid, high);
    }
}
  
void merge(int* arr, int low, int mid, int high)
{
    int i = low, j = mid + 1, k = 0;
    int* temp = (int*)calloc(high - low + 1, sizeof(int));
    while ((i <= mid) && (j <= high))
        if (arr[i] < arr[j])
            temp[k++] = arr[i++];
        else
            temp[k++] = arr[j++];
    while (j <= high) // if( i>mid )
        temp[k++] = arr[j++];
    while (i <= mid) // j>high
        temp[k++] = arr[i++];
  
    // copy temp[] to arr[]
    for (i = low, k = 0; i <= high; i++, k++)
        arr[i] = temp[k];
    free(temp);
}
  
int main()
{
    int a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    mergesort(a, 0, 7);
    for (int i = 0; i < 8; i++)
        printf("%d ", a[i]);
    return 0;
}

输出:

1 2 3 4 5 6 7 8