原地merg sort的一种实现

原文地址:

http://hi.baidu.com/void_while/blog/item/e5ed992237814541ad34defa.html

一、原因是 对原始算法每次合并都要动态开辟O(n)的空间且全部拷贝的做法耿耿于怀,部分灵感来自编程珠玑第2章的手摇算法。

二、代码

01/**
02 * 算法: 交换二对象
03 **/
04 template < typename T >
05 void t_swap ( T & v1 , T & v2 )
06 {
07     T t = v1 ; v1 = v2 ; v2 = t ;
08 }
09

10 /**
11 * 算法: 反转序列
12 **/
13 template < typename T >
14 void t_reverse ( T * v , size_t size )
15 {
16     size_t s = 0 , e = size - 1 ;
17     while ( s < e && s < size && e > 0 ) t_swap ( v [ s ++ ], v [ e -- ] );
18 }
19

20 /**
21 * 算法: 手摇算法,从指定位置旋转序列(见编程珠玑第二章)
22 **/
23 template < typename T >
24 void t_exchange ( T * v , size_t size , size_t n )
25 {
26     t_reverse ( v , n ); t_reverse ( v + n , size - n ); t_reverse ( v , size );
27 }
28

29 /**
30   * 算法: 合并二已排序的连续序列
31 **/
32 template < typename T >
33 void t_merge ( T & v , size_t size , size_t pos )
34 {
35     size_t fir = 0 , sec = pos ;
36     while ( fir < sec && sec < size )
37     {
38         while ( fir < sec && v [ fir ] <= v [ sec ] ) fir ++ ;
39         size_t maxMove = 0 ;
40         while ( sec < size && v [ fir ] > v [ sec ] ) maxMove ++ , sec ++ ;
41         t_exchange ( & v [ fir ], sec - fir , sec - fir - maxMove );
42         fir += maxMove ;
43     }
44 }
45

46 /**
47 * 算法: 归并排序
48 **/
49 template < typename T >
50 void t_merge_sort ( T * v , size_t size )
51 {
52     if ( size <= 1 ) return ;
53     t_merge_sort ( v , size / 2 );
54     t_merge_sort ( v + size / 2 , size - size / 2 );
55     t_merge ( v , size , size / 2 );
56 }

三、分析

  原理:合并时,将后半部最长可插入前半部的序列用手摇算法交换过去。

  效率:空间开销为0,时间效率还没与原始的归并排序做比较。预计在序列大致有序情况下会比原始算法效率有较大提高。

  最好情况:序列本身已排好序,只需做(n*logn)/2次比较,没有移动。

  最坏情况:每层合并都是诸如(2 4 6 8 10)(1 3 5 7 9)这样的交叉逆序子序列,需做(n/2)(n/2+1)logn次移动,不过这种情况几乎不可能出现

 

补充说明:
其实前面采用"旋转"算法将元素前移不是必须的, 可以将所要移动的元素之前的部分后移, 再将元素插入到合适的位置.比如前面说的对于序列1, 3, 5, 7, 2, 4, 6, 8, 第一步要将元素2前移至3之前, 可以将3,5,7后移, 然后将2插入到合适的位置.
但是这样有一个问题, 如果要移动的元素多了, 那么就需要更多的临时空间保存要前移的元素, 这样对空间就不是O(1)的了.而旋转算法可以做到O(1)的空间达到要求.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值