归并排序

代码来源:《数据结构(c++语言版)(第三版)》,邓俊辉编著,ISBN: 978-7-302-33064-6

归并排序可以理解为是反复调用二路归并算法实现。所谓的二路归并就是指,将两个有序序列合并成为一个有序序列。在每次迭代中,只需要关注两路的首元素,不断地把首元素提出放入总的序列中,从而实行合并。


归并排序的主体结构术语分治策略,代码如下:

template <typename T> //向量归并排序
void Vector<T>::mergeSort ( Rank lo, Rank hi ) { //0 <= lo < hi <= size
   if ( hi - lo < 2 ) return; //单元素区间自然有序,否则...
   int mi = ( lo + hi ) / 2; //以中点为界
   mergeSort ( lo, mi ); mergeSort ( mi, hi ); //分别排序
   merge ( lo, mi, hi ); //归并
}


算法实现如下:

template <typename T> //有序向量的归并
void Vector<T>::merge ( Rank lo, Rank mi, Rank hi ) { //各自有序的子向量[lo, mi)和[mi, hi)
   T* A = _elem + lo; //合并后的向量A[0, hi - lo) = _elem[lo, hi)
   int lb = mi - lo; T* B = new T[lb]; //前子向量B[0, lb) = _elem[lo, mi)
   for ( Rank i = 0; i < lb; B[i] = A[i++] ); //复制前子向量
   int lc = hi - mi; T* C = _elem + mi; //后子向量C[0, lc) = _elem[mi, hi)
   
for ( Rank i = 0, j = 0, k = 0; ( j < lb ) || ( k < lc ); ) { //B[j]和C[k]中的小者续至A末尾
      if ( ( k < lc ) || ( B[j] <= C[k] ) ) ) A[i++] = B[j++];
      if ( ( k < lc ) && ( ( C[k] <  B[j] ) ) ) A[i++] = C[k++];
   }
delete [] B; //释放临时空间B} //归并后得到完整的有序向量[lo, hi)

算法的实现可以这样理解:

  1. 设总队列为A,可移动变量i,两支分路为B和C,其中B代表[lo, mi)段,可移动变量j,C代表[mi, hi)段,可移动变量k;
  2. 为B开辟新的存储空间,并将A相应的前半部分复制给B;C无需开辟空间;
  3. 对B和C实现二路归并,条件是j和k都不越界;
  4. 最后释放B的空间。

在这段代码中需要注意,若C先耗尽(越界),则将B继续复制给A;若B先耗尽(越界),则将C继续复制到A。但是C本身就在A中,所以这一步多余,可以修改循环条件为:


for ( Rank i = 0, j = 0, k = 0; ( j < lb ) || ( k < lc ); ) { //B[j]和C[k]中的小者续至A末尾
      if ( ( k < lc ) || ( B[j] <= C[k] ) ) A[i++] = B[j++];
      if ( ( k < lc ) && ( ( C[k] <  B[j] ) ) ) A[i++] = C[k++];
}


使得当B越界时,结束循环。


可以证明,该算法的时间复杂度为O(nlogn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值