【排序】归并排序

来源:互联网 发布:目前那个网络云盘好用 编辑:程序博客网 时间:2024/06/07 21:58

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。


2-路归并算法

1.算法基本思路

     设两个有序的子文件(相当于输入堆)放在同一向量中相邻的位置上:SR[low..m],SR[m+1..high],先将它们合并到一个局部的暂存向量TR(相当于输出堆)中,待合并完成后将TR复制回SR[low..high]中。

2.合并过程
     (1)比较两个子序列的第一个元素的关键字(SR[low].key和SR[m+1].key),将较小的那个元素放置到暂存向量TR[low++]中,然后再用该元素的下一个元素代替它进行下一次的比较(较大的元素不变),知道其中一个子序列为空为止。然后把不为空的子序列全部复制到TR[low]的尾部。

3.算法实现,算法演示:参见动画演示

template<class T> void Merge(T SR[],T TR[],int low,int mid,int high) //归并排序   {      int i = low;      int j = mid + 1;      int k = 0;      while(i <= mid && j <= high)      {          if(SR[i] < SR[j])  //进行排序存入动态分配的数组中               TR[k++] = SR[i++];          else              TR[k++] = SR[j++];      }      while(i <= mid) //如果前一半中还有未处理完的数据,按顺序移入动态分配的数组内           TR[k++] = SR[i++];      while(j <= high) //如果后一半中还有未处理完的数据,按顺序移入动态分配的数组内           TR[k++] = SR[j++];      for( k = 0, i = low;i <= high;k++,i++) //将排序好的数据移回到原序列中           SR[i] = TR[k];}

    归并排序的三个步骤是:

①分解:将当前区间一分为二,即求分裂点:m=[low+hight]/2;

②求解:递归地对两个子区间R[low..mid]和R[mid+1..high]进行归并排序;

③组合:将已排序的两个子区间R[low..mid]和R[mid+1..high]归并为一个有序的区间R[low..high]。

递归的终结条件:子区间长度为1(一个记录自然有序)。

算法图解:



具体代码:

template<class T> void MSort(T a[],T temp[],int low,int high)  {      int mid;      if(low < high)      {          mid = (low + high) / 2; //进行分裂           MSort(a,temp,low,mid); //将前一半继续分裂           MSort(a,temp,mid + 1,high); //将后一半继续分裂           Merge(a,temp,low,mid,high); //进行归并排序       }  }  
template<class T> inline void MergeSort(T* SR,int len) //归并排序算法   {      T* TR = (T*)malloc(sizeof(T) * len); //动态分配一个额外的存储空间       MSort(SR,TR,0,len-1); //分裂然后调用归并排序       free(TR); //释放内存   }  

二、算法分析(在一般情况下很少使用2-路归并排序法进行内部排序)

1、稳定性

      其最大特点就是,归并排序是一种稳定的排序。

2、存储结构要求
     可用顺序存储结构。也易于在链表上实现。

3、时间复杂度
     无论是在最好情况下还是在最坏情况下均是O(nlgn)。

4、空间复杂度
     需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
  
0 0