排序算法——归并排序(二路归并)

时间:2019-02-16
本文章向大家介绍排序算法——归并排序(二路归并),主要包括排序算法——归并排序(二路归并)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

二路归并的基本思想:将含有n个记录的原始序列看做n个长度1的子序列。从第一个子序列开始,将相邻的两个子序列合并,得到长度为2或1(最后只剩下1个子序列的情况)的子序列。如此重复成对归并,直到序列的长度等于原始序列的长度时为止。

基本过程:两个有序序列的合并。

排序过程如下图:

C++代码:

//一次二路归并过程
//对序列a[0]...a[length-1]进行一次二路归并排序,每个子序列的长度为size
void Merge(int a[], int swap[], int size, int length) {
	int i, j;
	int begin1, end1, begin2, end2;//分别表示两个子序列的首尾下标
	int sp;//表示已经归并的元素个数
	begin1 = 0;//第一个子序列的起始下标
	sp = 0;
	while (begin1 + size <= length - 1) {   //测试是否存在两个可以合并的子序列
		begin2 = begin1 + size;            //第二个子序列的起始下标
		end1 = begin2 - 1;                   //第一个子序列的结束下标
		if (begin2 + size > length) {
			end2 = length - 1;    //第二个子序列的结束下标(第二个子序列长度不足size)
		}
		else {
			end2 = begin2 + size - 1;
		}
		//下面合并两个子序列
		for (i = begin1, j = begin2; i <= end1&&j <= end2;) { //注意是小于等于
			if (a[i] <= a[j]) {
				swap[sp++] = a[i++];
			}
			else {
				swap[sp++] = a[j++];
			}
		}
		//其中某一个子序列已经全部归并
		while (i <= end1) {//第一个子序列还有剩余
			swap[sp++] = a[i++];
		}
		while (j <= end2) {//第二个子序列还有剩余
			swap[sp++] = a[j++];
		}
		begin1 = end2 + 1;//改变子序列开头以开启下一对序列的合并
	}
	//将原始序列中无法配对的子序列(最后落单的序列)放入结果序列中
	for (i = begin1; i < length;) {
		swap[sp++] = a[i++];
	}
}

int * MergeSort(int a[], int length) {
	int *result = new int[length];//存储归并结果
	int size = 1;//记录子序列的大小
	while (size < length) {//合并到子序列长度等于原始序列长度时为止

		Merge(a,result,size,length); //归并的结果存于result
		size = size * 2;		

		Merge(result, a, size, length);//归并的结果存于a
		size = size * 2;
	}
	return a;
}

n个记录进行二次归并时,归并的次数为log_2n,每次归并过程中,记录的比较次数不超过n次。所以二次归并的时间复杂度为Ο(nlog_2⁡n),空间复杂度为Ο(n)。二路归并排序是稳定的排序,这是它相对于快速排序的最大优点。