合并排序算法是用分治的策略实现对n个元素进行排序的算法。其基本思想是:将待排序的元素分成大小大致相同的两个子集合,分别对两个子集合进行排序,最终将排好序的子集合合并成所要求的排好序的集合。合并排序算法可以递归地描述如下:
template <class T>
void MergeSort( T a[], int left, int right ){
if( left < right ){ //至少要有2个元素
int i = ( left + right ) / 2; // 取中点
MergeSort( a, left, i ); //对左边进行排序
MergeSort( a, i + 1, right );//对右边进行排序
Merge( a, b, left, i, right );//合并到数组b,真正进行排序就是在这里进行的
Copy( a, b, left, right ); //复制回数组a
}
}
这个递归方程T( n ) = O( nlongn )。由于排序问题的计算下界为Ω(nlongn),所以啊合并算法是一个渐进最优的算法。下面举个例子。
对于算法MergeSort,还可以进行改进,例如我们可以消除递归。事实上,算法MergeSort的递归过程只是将待排序集合一分为二,直至只剩下一个元素为止,然后不断的合并两个排序号的数组段。按此机制,可以首先将数组a中相邻元素两两配对。用合并排序将他们排序,构成n / 2组长度为2的排好序的子数组段,然后将他们排序成长度为4的排好序的子数组段,如此继续下去,直至整个数组排好序。
按此思想,相除递归的合并排序算法可以描述如下:
template <class T>
void MergeSort( T a[], int n ){
//消除递归的做法
T* b = new T[n];
int s = 1;
while( s < n ){
MergePass( a, b, s, n );//合并到b数组
s += s;
MergePass( b, a, s, n );//合并到a数组
s += s;
}
}
其中,需要重载T类型元素的“<=”符号。
下面给出其他出现函数的代码
template <class T>
void Merge( T a[], T b[], int l, int m, int r ){
int i = l;
int j = m+1;
int k = l;
while( i <= m && j <= r )
if( a[ i ] <= a[ j ] ) b[k++] = a[i++]; //较小的放在前面
else b[k++] = a[ j++ ];
if( i > m )for( int q = j; q <= r; ++q ) b[ k++ ] = a[ q ];//左边还有元素没有放进b时,
else for( int q = i; q <= m; ++q ) b[ k++ ] = a[ q ];//右边还有元素没有放进b时,
}
template <class T>
void MergePass( T x[], T y[], int s, int n ){
int i = 0;
while( i <= n - 2 * s ){//预留出2 * s个位置,
Merge( x, y, i, i + s - 1, i + 2 * s - 1 );
i += 2 * s;
}
if( i + s < n )Merge( x, y, i, i + s - 1, n - 1 ); //要合并的左右子集中,左子集够s个,但是右子集不够
else for( int j = i; j <= n - 1; ++j ) y[j] = x[j]; //要合并的左右子集中,连左子集都不够s个了
}
template <class T>
void Copy( T a[], T b[], int l, int r ){
int i;
for( i = l; i <= r; ++i ){
a[ i ] = b[ i ];
}
}