排序算法(六)---- 归并排序

对于归并排序,与快速排序一样,巧妙的应用了分治算法的核心思想,它将整个序列分成若干组子序列,对这些子序列进行排序后,在一步一步进行合并有序子序列,从而使得整个序列达到有序。
但针对于归并排序,有着两种不同的排序方式,一是通过整个序列进行着手,将这个序列进行一步一步的划分,自顶向下进行处理,主要步骤包括序列划分,子序列排序,以及合并,而这一方法可以通过递归来实现;与之相对的就是另外一种方式,自底向上,从最小子序列着手,将其进行两两合并,一步一步得到整个有序序列,而这也是我们归并排序的非递归实现方式
《排序算法(六)---- 归并排序》

①自顶向下(递归) 方法如下:

void Merge(int arr[],int left,int right,int mid,int* tmp)
{
       int i=left;
       int j=mid+1;
       int idx=0;
       while(i<=mid&&j<=right)
       {
              if(arr[i]<arr[j])
                     tmp[idx++]=arr[i++];
              else
                     tmp[idx++]=arr[j++];
       }

       while(i<=mid)
       {
              tmp[idx++]=arr[i++];
       }
       while(j<=right)
       {
              tmp[idx++]=arr[j++];
       }

}

void MergeSort_Nor(int arr[],int left,int right,int* tmp)
{
       if(left<right)
       {
              int mid=(left&right)+((left^right)>>1);
              MergeSort_Nor(arr,left,mid,tmp);
              MergeSort_Nor(arr,mid+1,right,tmp);
              Merge(arr,left,right,mid,tmp);
              memcpy(arr+left,tmp,(right-left+1)*sizeof(arr[0]));
       }
}

void MergeSort(int arr[],int size)
{
       int* tmp=new int[size];
       int left=0;
       int right=size-1;
       MergeSort_Nor(arr,left,right,tmp);
       delete[] tmp;
}

②自底向上(非递归) 方法如下:

void Merge(int arr[],int left,int right,int mid,int* tmp)
{
       int i=left;
       int j=mid+1;
       int idx=0;
       while(i<=mid&&j<=right)
       {
              if(arr[i]<arr[j])
                     tmp[idx++]=arr[i++];
              else
                     tmp[idx++]=arr[j++];
       }

       while(i<=mid)
       {
              tmp[idx++]=arr[i++];
       }
       while(j<=right)
       {
              tmp[idx++]=arr[j++];
       }

}

void MergeSort(int arr[],int size)
{
       int* tmp=new int[size];
       int gap=1;
       while(gap<size)
       {
              for(int i=0;i<size;i+=2*gap)
              {
                     int left=i;
                     int right=i+2*gap-1;
                     int mid=i+gap-1;
                     if(right>=size)//注意越界
                           right=size-1;
                     if(mid>=size)//注意越界
                           mid=size-1;
                     Merge(arr,left,right,mid,tmp);
                     memcpy(arr+left,tmp,(right-left+1)*sizeof(arr[0]));
              }
              gap*=2;
       }

       delete[] tmp;
}

值得注意的是,归并排序不管是非递归方法,还是递归方法,都需要辅助空间的参与,但是对于递归而言,一次递归就申请一次空间会降低效率,而且需要注意释放空间,所以这里在外部直接申请出一块足够的空间,然后将其指针作为参数进行传递,而在外部进行释放,也是相当方便。

对于归并排序的时间复杂度为O(NlogN),空间复杂度为O(N),而且归并排序是稳定的

与前面所有的排序算法不一样,归并排序属于外部排序,而对于外部排序而言,与内部排序最大的区别在于外部排序在进行排序时,并不需要得到所有数据,可以将大量的数据分成若干组,分别对其进行排序,最后再综合起来排序,适合与大量数据的排序

点赞