、原因是对原始算法每次合并都要动态开辟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次移动,不过这种情况几乎不可能出现。