归并排序

//归并排序  复杂度O(n*logn)
int MergeSort(int a[], int n)
{
   int *tmp = malloc(sizeof(int)*n);
   if(tmp == NULL)
         return 0;
   mergesort(a,0,n-1,tmp);
   free(tmp);
   return 1;
}
//所谓的“归”  采用递归思想
void mergesort(int a[],int first, int last, int tmp[])
{
    int mid = (first + last)/2;
    if(first < last)
    {
        mergesort(a,first,mid,tmp);          //排序左边
        mergesort(a,mid+1,last,tmp);         //排序右边
        MergeTwoArray(a,first,mid,last,tmp); //将已经排序好的左右两边“并”起来
    }
}
//所谓的“并”
void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
{
    int i = first, j = mid + 1;
    int k = 0;
    while(i <= mid && j <= last)     
    {
       if(a[i] <= a[j]) 
            {
             tmp[k++] = a[i++];
            }
       else 
         {
             tmp[k++] = a[j++];
         }
    }

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

    if(j<=last) 
    {
        while(j<=last)
        {
            tmp[k++] = a[j++];
        }
    }

    for(i=0;i<k;i++)
    {
        a[first+i]=tmp[i];
    }
}

 

--------------------------------------------------------------- 8月28日看了MIT算法的归并排序 对“并”进行代码优化-------------------------------------------------------------

void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
{
  for(int k=first;k<=last;k++)
  {
     tmp[k] = a[k];                //copy
  }

  int i=first.j=mid+1;

  for(k=first;k<=last;k++)        //merge
  {
     if(i>mid)                a[k]=tmp[j++];
     else if(j>last)          a[k]=tmp[i++];
     else if(tmp[i] < tmp[j]) a[k] = tmp[i++];
     else                     a[k] = tmp[j++];
  }
}

 

 优化归并排序:

一、考虑为何归并排序不适合特别小的数组?

      因为申请额外空间,还会增加调用函数开销。而和插入排序比较而言,由于数组规模特别小,时间上并无太大差别。

      因此改进方法就是进行切分。对于小于某个数组规模的数组进行插入排序。见代码

二、假设左右两边数组排序后已经是有序了,那就可以跳过合并的步骤,见代码

三、对于tmp辅助数组,可以不用来回拷贝,而是在这两个数组之间交替进行,只要保证最后拷贝回原来的数组即可。

void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
{
  for(int k=first;k<=last;k++)
  {
     tmp[k] = a[k];                //copy
  }

  int i=first.j=mid+1;

  for(k=first;k<=last;k++)
  {
     if(i>mid)                a[k]=tmp[j++];
     else if(j>last)          a[k]=tmp[i++];
     else if(tmp[i] < tmp[j]) a[k] = tmp[i++];
     else                     a[k] = tmp[j++];
  }
}


#define CUTOFF 3 void merge_sort(int a[], int tmp[], int first, int last) { if(last <= first + CUTOFF - 1) { insert_sort(a,first,last); return; } int mid=first + (last-first)/2; merge_sort(a,tmp,first,mid); merge_sort(a,tmp,mid+1,last); if(a[mid] <= a[mid+1]) return; MergeTwoArray(a,tmp,first,mid,last); }

时间复杂度证明:

1.树状图法:

2.数学证明法:

3.归纳法

非递归的归并排序:

//非递归的归并排序
void MergeSort(int a[], int n)
{
    int length = 1;
    int *tmp = malloc(sizeof(int)*n);
    if(tmp == NULL)
    {
      return 0;
    }

    while(length < N)
    {
        mergesort(A,tmp,N,length);
        length *= 2;
        mergesort(tmp,A,N,length);
        length *= 2;
    }
    free(tmp);
    return 1;
}


//所谓的并
void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
{
    int i = first, j = mid + 1;
    int k = 0;
    while(i <= mid && j <= last)     
    {
       if(a[i] <= a[j]) 
            {
             tmp[k++] = a[i++];
            }
       else 
         {
             tmp[k++] = a[j++];
         }
    }

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

    if(j<=last) 
    {
        while(j<=last)
        {
            tmp[k++] = a[j++];
        }
    }

    for(i=0;i<k;i++)
    {
        a[first+i]=tmp[i++];
    }
}


//非递归的“归”
void mergesort(int a[],int tmp[],int N, int length)
{
    
    for(int i=0;i <= N-2*length;i += 2*length)
    {
      MergeTwoArray(a,i,i+length,i+2*length-1,tmp);
    }

    if(i+length >= N)
    {
     for(int j=i;j<N;j++)
         tmp[j] = a[j];
    }
    else
    {
      MergeTwoArray(a,i,i+length,i+2*length-1,tmp);
    }
}

非递归精简版:

void merge_sort2(int a[], int N)
{
    tmp = malloc(sizeof(int)*N);
    for(int sz=1;sz<N;sz*=2)
    {
       for(int lo=0;lo<N-sz;lo+=sz+sz)
       {
          MergeTwoArray(a,lo,lo+sz-1,min(lo+sz+sz-1,N-1),tmp);
       }
    }
}
原文地址:https://www.cnblogs.com/dzy521/p/9383136.html