定义:
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个典型应用.应该将已经有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. [摘录于维基百科]
无论哪一种归并算法的实现,它都需要用到一个MergeArray函数实现两个有序数组的合并.如下:
/** * 首先定义一个新数组b存储合并后的数据信息,具体的合并过程即架循环遍历 * 两个数组,如果前一部分数组元素小于后一部分数组元素则i++(前数组的循环 * 变量),否则j++(后数组的循环变量).当有一个数组遍历结束时,跳出循环. * 跳出之后,如果另一个数组没有遍历结束,则将其剩余元素存储在p数组中, * 否则跳过. **/
void MergeArray ( int a[] , int left , int mid , int right )
{
// 循环变量i,j分别为两部分数组的检测指针
int i = left , j = mid + 1 , k = 0 , m , p ;
int b[N] ;
// 其中任意一个数组访问结束,则循环结束
while ( i <= mid && j <=right ) {
if ( a[i] <= a[j] ) {
// 前一个数组当前元素不大于后一个数组,则i++
b[k++] = a[i++] ;
} else {
// 否则j++
b[k++] = a[j++] ;
}
}
// 前一个数组没有遍历结束则继续循环,使其存储在b数组中
while ( i <= mid ) {
b[k++] = a[i++] ;
}
// 后一个数组没有遍历结束则继续循环,使其存储在b数组中
while ( j <= right ) {
b[k++] = a[j++] ;
}
}
因为递归式的归并排序实现比较简单,在这里我就不再介绍. 因此下面主要分享非递归方法的实现,分别是:一般排序和自然排序.
A. 非递归归并排序の一般排序:
从小的部分实现,首先是一个元素为一组,每次以2的倍数增长,每一次分组后两个小组为一组进行合并即调用MergeArray合并函数实现合并,其实就是"从小到大"的思想,与递归的思想刚好相反.(其中有的细节可以参考代码,重点是理解代码中的注释)
/************************************************************************* ** > Name : FDG_Combine.c ** > Author: LiYingXiao (Sweethreart502) ** > Mail : liyingxiao502@gmail.com ** > Blog : http://blog.csdn.net/u013166575 ** > Created Time: 2015年10月7日 星期一 20时34分15秒 ************************************************************************/
#include <iostream>
#define Max 5
// 数组合并算法
void MergeArray ( int * a , int left , int middle , int right , int n )
{
int * p = new int[n] ;
int i = left , j = middle + 1 , k = 0 ;
// 架循环使得两个数组按照大小顺序存储在p数组中
while ( i <= middle && j <= right ) {
if ( a[i] < a[j] ) {
p[k++] = a[i++] ;
} else {
p[k++] = a[j++] ;
}
}
while ( i <= middle ) {
p[k++] = a[i++] ;
}
while ( j <= right ) {
p[k++] = a[j++] ;
}
// 将合并后的信息赋值给原数组
for ( i = 0 ; i < n ; i++ ) {
a[left+i] = p[i] ;
}
delete [] p ;
}
// 归并排序算法
void MergeSort ( int * a , int n )
{
int length = 1 ;
int begin ;
for ( length = 1 ; length < n ; length *= 2 ) {
// 每一次的分组划分合并处理,都是从下标0开始的
begin = 0 ;
while ( ( begin + 2 * length ) < n ) {
// 调用合并函数,实现两两小数组合并
MergeArray ( a , begin , ( 2*begin + 2*length -1 ) / 2 , begin + 2*length - 1 , 2*length ) ;
// 循环到下一对合并的小数组
begin += 2*length ;
}
// 如果剩下的长度不足够2*length但begin+length<n,则继续将其合并
if ( ( begin + length ) < n ) {
MergeArray ( a , begin , begin + length - 1 , n - 1 , n ) ;
}
}
}
// 主函数
int main ( )
{
int array[Max] = { 0 } ;
std::cout << "Please input the " << Max << " elements of the array : " << std::endl ;
for ( int i = 0 ; i < Max ; i++ ) {
std::cin >> array[i] ;
}
// 调用归并排序函数
MergeSort ( array , Max ) ;
// 排序结束后的数组进行输出展示
std::cout << std::endl << "The sorted array is : " << std::endl ;
for ( int i = 0 ; i < Max ; i++ ) {
std::cout << array[i] << " " ;
}
std::cout << std::endl ;
return 0 ;
}
B. 非递归归并排序の自然归并:
自然合并的核心主要是一个Pass函数,这个函数中设置了一个array数组,来存放每一组有序元素的起始元素的下标,最后再将最后一个元素的下标+1存放为array数组的最后一个元素,这样,在后面的合并实现中会显现出这样记录的原因.(其中具体实现可以参考代码,重点是理解代码中的注释)
/************************************************************************* ** > Name : Nature_Combine.c ** > Author: LiYingXiao (Sweethreart502) ** > Mail : liyingxiao502@gmail.com ** > Blog : http://blog.csdn.net/u013166575 ** > Created Time: 2015年10月7日 星期一 20时34分15秒 ************************************************************************/
#include <iostream>
#define N 10
// 定义全局数组,记录每个子数组的其实坐标
int array[N] ;
// 两个数组合并函数
void MergeArray ( int a[] , int left , int right , int mid )
{
// 循环变量i,j分别为两部分数组的检测指针
int i = left , j = mid + 1 , k = 0 , m , p ;
int b[N] ;
while ( i <= mid && j <=right ) {
if ( a[i] <= a[j] ) {
b[k++] = a[i++] ;
} else {
b[k++] = a[j++] ;
}
}
while ( i <= mid ) {
b[k++] = a[i++] ;
}
while ( j <= right ) {
b[k++] = a[j++] ;
}
for ( p = 0 , m = left ; m <= right ; p++ , m++ ) {
a[m] = b[p] ;
}
}
// 扫描算法(这个函数是理解的关键!!!)
int Pass ( int a[] , int n )
{
int num = 0 , i ;
int biger = a[0] ;
array[num++] = 0 ; // 将全局数组下标为0的值记为0
for ( i = 1 ; i < n ; i++ ) {
if ( a[i] >= biger ) {
biger = a[i] ;
} else {
array[num++] = i ;
biger = a[i] ;
}
}
// array数组存储每一组有序的数组的起始元素的下标,同时存储最后一个元素的下标+1,为了方便最后一组元素的合并二需要!!!
array[num++] = N ;
return num ; // num此时为数组最后一个元素下标+1
}
// 归并排序的自然实现
void MergeSort ( int a[] , int n , int left , int right )
{
int i ;
int num = Pass ( a , n ) ;
while ( num != 2 ) {
// num = 2 说明已经排序完成即只存储了下标为1的元素
// 每循环一次,执行一次pass函数
for ( i = 0 ; i < num ; i += 2 ) {
// array[i]即合并数据的起点; array[i+2]后一组的后面一组的起点-1即合并数据的终点; array[i+1]后一组的起点-1即合并数据的中点
MergeArray ( a , array[i] , array[i+2] - 1 , array[i+1] - 1 ) ;
// num = Pass ( a, n ) ;
}
num = Pass ( a , n ) ;
}
}
// 主函数
int main ( )
{
int a[N] ;
int i ;
std::cout << "Printf input the num :" << std::endl ;
for ( i = 0 ; i < N ; i++ ) {
std::cin >> a[i] ;
}
MergeSort ( a , N , 0 ,N - 1 ) ;
std::cout << "Output the num :" << std::endl ;
for ( i = 0 ; i < N ; i++ ) {
std::cout << a[i] << " " ;
}
std::cout << std::endl ;
return 0 ;
}
以上就是我今天所要总结的归并排序算法的实现.欢迎大家互相讨论,提出意见.