双路归并排序法(自上向下)

算法原理

    归并排序(Merge Sort)是利用“归并” 技术来进行排序。归并是指将若干个已排序的 子 文件 合并 成 一个 有序 的 文件。

    两路 归并 算法 的 基本 思路: 设 两个 有序 的 子 文件( 相当于 输入 堆) 放在 同一 向量 中 相邻 的 位置 上: A[ low… m], a[ m+ 1… high], 先 将它 们 合并 到 一个 局部 的 暂存 向量 Temp( 相当于 输出 堆) 中, 待 合并 完成 后 将 Temp 复制 回 A[ low... high] 中。

    归并 排序 有两 种 实现 方法: 自 底 向上 和 自 顶 向下。

    自 底 向上 方法 的 基本 思想:

    (1) 第 1 趟 归并 排序 时, 将 待 排序 的 文件 A[ 1... n] 看作 n 个 长度 为 1 的 有序 子 文件, 将 这些 子 文件 两两 归并。 若 n 为 偶数, 则 得到 n/ 2 个 长度 为 2 的 有序 子 文件; 若 n 为 奇数, 则 最后 一个 子 文件 不 参与 归并。 故 本 趟 归并 完成 后, 前 n/ 2 个 有序 子 文件 长度 为 2, 但 最后 一个 子 文件 长度 仍 为 1。

    (2) 第 2 趟 归并 则 是将 第 1 趟 归并 所 得到 的 n/ 2 个 有序 的 子 文件 两两 归并, 如此 反复, 直到 最后 得到 一个 长度 为 n 的 有序 文件 为止。

    (3) 上述 每次 归并 操作, 均 是将 两个 有序 的 子 文件 合并 成 一个 有序 的 子 文件, 故称 其为“ 二路 归并 排序”。 类似 地, 有 k( k> 2) 路 归并 排序。

    自 顶 向下 算法 的 设计, 形式 更为 简洁。 设 归并 排序 的 当前 区间 是 A[ low... high], 步骤 如下。

    (1) 分解: 将 当前 区间 一分为二, 即 求 分裂 点。

    (2) 求解: 递归 地 对 两个 子 区间 A[ low... mid] 和 A[ mid+ 1... high] 进行 归并 排序。

    (3) 组合: 将 已 排序 的 两个 子 区间 A[ low... mid] 和 A[ mid+ 1... high] 归并 为 一个 有序 的 区间 R[ low… high]。

    (4) 递归 的 终结 条件: 子 区间 长度 为 1( 一个 记录 自然 有序)。

算法草稿

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define SUCCESS		0
#define PARAM_ERR	-1
#define ALLOC_ERR	-2

/*
 * 合并两个子数组 [lstart, lend] [rstart, rend]
 */
int MergeImpl(int * array, int * temp,  int lstart, int lend, int rstart, int rend){
	if(NULL == array || NULL == temp){
		printf("%s para error\n", __func__);
		return PARAM_ERR;
	}

#if 1
	int size = 0; /* 两个待合并的素组总长度 */
	int i = 0, j = 0, k = 0;

	size = (lend - lstart +  1) + (rend - rstart + 1);
	i = lstart;
	j = rstart;
	k = 0;
	
#ifdef DEBUG
	int m = 0;
	printf("Befor %s: size = %d \n", __func__, size);	
	for(m = lstart; m <= rend ; m++){
		printf("array[%d] = %d ", m, array[m]); 	
	}
	printf("\n");
#endif

	/*清空待合并数组*/
	memset(temp, 0x0, size * sizeof(int));

	/* 升序 */
	while ( (i <= lend) && (j <= rend)){
		if(array[i] <= array[j]){
			temp[k++] = array[i++];
		} else {
			temp[k++] = array[j++];
		}
	}

	/* 左子组还有 */
	while (i <= lend){
		temp[k++] = array[i++];
	}
	
	/* 右子组还有 */
	while (j <= rend){
		temp[k++] = array[j++];
	}	

	/*
	 * 合并后的数组,复制回array 
	 * 因为左右两个子组是相邻的,所以从lstart顺序复制如array
	 */
	i = lstart;
	for(k = 0; k < size; k++){
		array[i++] = temp[k];		
	}

#ifdef DEBUG
	printf("After: %s \n", __func__);
	for(m = 0; m < size ; m++){
		printf("temp[%d] = %d ", m, temp[m]);		
	}
	printf("\n");

	for(m = lstart; m <= rend ; m++){
		printf("array[%d] = %d ", m, array[m]);		
	}

	printf("\n\n");
#endif


#else
	int size = 0; /* 两个待合并的素组总长度 */
	int lpos = 0, rpos = 0, tpos = 0, k = 0;

	size = rend - lstart + 1;
	lpos = lstart;
	rpos = rstart;
	tpos = lstart;

	/* 升序 */
	while ( (lpos <= lend) && (rpos <= rend)){
		if(array[lpos] <= array[rpos]){
			temp[tpos++] = array[lpos++];
		} else {
			temp[tpos++] = array[rpos++];
		}
	}


	/* 左子组还有 */
	while (lpos <= lend){
		temp[tpos++] = array[lpos++];
	}
	
	/* 右子组还有 */
	while (rpos <= rend){
		temp[tpos++] = array[rpos++];
	}	

	/*
	 * 合并后的数组,复制回array 
	 * 因为左右两个子组是相邻的,所以从lstart顺序复制如array
	 */
	for(k = 0; k < size; k++, rend--){
		array[rend] = temp[rend];	
	}

#endif
	return SUCCESS;
	
}

/*
 * 本函数真正的合并排序实现
 */
int MergeSortImpl(int * array, int * temp,  int low, int high){
	if(NULL == array || NULL == temp){
		printf("%s para error\n", __func__);
		return PARAM_ERR;
	}

	int i = 0, j = 0;
	int size = 0; /* 排序分组大小 */
	int mid = 0;
	
	size =  high - low + 1;
	/* 递归终止条件,数组中只有一个元素*/
	if(size <= 1){
		goto out;		
	}

	/*
	 * 两路合并排序,自定向下,取得中间点 
	 * 注意 low 和 high 的中间的不是 size /2 而是 (low + high) / 2 ! 千万注意
	 */
	mid = (low + high) / 2; /*左子组:[low, mid], 右子组:[mid+1, high]*/
	
	/* 对左子组两路合并排序*/
	MergeSortImpl(array, temp, low, mid);

	/* 对右子组两路合并排序*/
	MergeSortImpl(array, temp, mid + 1 , high);

	/* 对已排序的两个子组进行合并 */
	MergeImpl(array, temp, low, mid, mid + 1, high);

out:
	return SUCCESS;
}


int MergeSort(int * array, int size){
	if(NULL == array){
		printf("%s para error\n", __func__);
		return PARAM_ERR;
	}

	int * temp = NULL;

	/*这里是合并排序的接口,完成准备工作*/
	temp = (int *) malloc (size * sizeof(int));
	if(NULL == temp){
		printf("%s alloc memory error\n",__func__);
		return ALLOC_ERR;
	}

	MergeSortImpl(array, temp, 0, size - 1);

	/* 删除已分配空间 */
	free(temp);
	temp = NULL;

	return SUCCESS;	
}


int main(int argc, char ** argv){
	int array[10] = {7,3,5,8,0,9,1,2,4,6};
	int i = 0;

	printf("Before sort: \n");
	for(i = 0; i < 10; i++){
		printf("  %d  ", array[i]);
	}
	printf("\n");

	MergeSort(array, 10);

	printf("after sort: \n");
	for(i = 0; i < 10; i++){
		printf("  %d  ", array[i]);
	}
	printf("\n");
	
	return 0;
}

调试编译

gcc MergeSort.c -DDEBUG

调试输出

Before sort:
  7    3    5    8    0    9    1    2    4    6
Befor MergeImpl: size = 2
array[0] = 7 array[1] = 3
After: MergeImpl
temp[0] = 3 temp[1] = 7
array[0] = 3 array[1] = 7

Befor MergeImpl: size = 3
array[0] = 3 array[1] = 7 array[2] = 5
After: MergeImpl
temp[0] = 3 temp[1] = 5 temp[2] = 7
array[0] = 3 array[1] = 5 array[2] = 7

Befor MergeImpl: size = 2
array[3] = 8 array[4] = 0
After: MergeImpl
temp[0] = 0 temp[1] = 8
array[3] = 0 array[4] = 8

Befor MergeImpl: size = 5
array[0] = 3 array[1] = 5 array[2] = 7 array[3] = 0 array[4] = 8
After: MergeImpl
temp[0] = 0 temp[1] = 3 temp[2] = 5 temp[3] = 7 temp[4] = 8
array[0] = 0 array[1] = 3 array[2] = 5 array[3] = 7 array[4] = 8

Befor MergeImpl: size = 2
array[5] = 9 array[6] = 1
After: MergeImpl
temp[0] = 1 temp[1] = 9
array[5] = 1 array[6] = 9

Befor MergeImpl: size = 3
array[5] = 1 array[6] = 9 array[7] = 2
After: MergeImpl
temp[0] = 1 temp[1] = 2 temp[2] = 9
array[5] = 1 array[6] = 2 array[7] = 9

Befor MergeImpl: size = 2
array[8] = 4 array[9] = 6
After: MergeImpl
temp[0] = 4 temp[1] = 6
array[8] = 4 array[9] = 6

Befor MergeImpl: size = 5
array[5] = 1 array[6] = 2 array[7] = 9 array[8] = 4 array[9] = 6
After: MergeImpl
temp[0] = 1 temp[1] = 2 temp[2] = 4 temp[3] = 6 temp[4] = 9
array[5] = 1 array[6] = 2 array[7] = 4 array[8] = 6 array[9] = 9

Befor MergeImpl: size = 10
array[0] = 0 array[1] = 3 array[2] = 5 array[3] = 7 array[4] = 8 array[5] = 1 array[6] = 2 array[7] = 4 array[8] = 6 array[9] = 9
After: MergeImpl
temp[0] = 0 temp[1] = 1 temp[2] = 2 temp[3] = 3 temp[4] = 4 temp[5] = 5 temp[6] = 6 temp[7] = 7 temp[8] = 8 temp[9] = 9
array[0] = 0 array[1] = 1 array[2] = 2 array[3] = 3 array[4] = 4 array[5] = 5 array[6] = 6 array[7] = 7 array[8] = 8 array[9] = 9

after sort:
  0    1    2    3    4    5    6    7    8    9
发布了191 篇原创文章 · 获赞 43 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/leoufung/article/details/104321934
今日推荐