04-归并排序

归并排序:顾名思义,就是不断的将两个有序的子序列归并成一个大的序列。所以核心操作就是有序子列的归并,如果有两个子列,共有N个元素,那么归并的时间复杂度是T(N)=O(N)。有了归并算法,我们采用易于理解的方式,分而治之的思想,也就是不断地递归将大的序列划分成小的序列,当序列只有一个元素的时候(自身有序),就是递归终止条件。

//归并排序-递归实现
//O(nlogn)  O(n)
#include<bits/stdc++.h>
using namespace std;

void merge(vector<int>& arr,vector<int>& aux,int L,int R,int RightEnd) {
	//将有序的A[L]-A[R-1]和A[R]-A[RightEnd]归并成一个有序序列
	int LeftEnd = R - 1; //左边终点位置
	int i = L;   //有序序列起始位置
	int count = RightEnd - L + 1; //本次归并元素总个数

	while (L<=LeftEnd && R<=RightEnd) {
		if (arr[L] <= arr[R])
			aux[i++] = arr[L++];  //将左边元素复制到aux
		else 
			aux[i++] = arr[R++];  //将右边元素复制到aux
	}

	while (L <= LeftEnd)
		aux[i++] = arr[L++];      //直接复制左边剩下的
	while (R <= RightEnd)         
		aux[i++] = arr[R++];      //直接复制右边剩下的

	for (i = 0; i < count; i++,RightEnd--) //将有序序列aux复制回arr
		arr[RightEnd] = aux[RightEnd];
}

void MSort(vector<int>& arr,vector<int>& aux,int L,int RightEnd) {
	int mid = 0;
	if(L<RightEnd) {
		mid = L + (RightEnd - L) / 2;
		MSort(arr,aux,L,mid);            //递归解决左边
		MSort(arr,aux,mid+1,RightEnd);   //递归解决右边
		merge(arr,aux,L,mid+1,RightEnd); //合并两端有序序列
	}
}

void mergeSort(vector<int>& arr) { //归并排序对外接口,使得排序接口一致
	int n = arr.size();
	vector<int> aux(n,0);
	MSort(arr,aux,0,n-1);
}

int main() {
	vector<int> arr = { 8,6,10,7,9,4,3,2,5,1 };
	mergeSort(arr);
	for (auto x : arr) {
		cout << x << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}
1 2 3 4 5 6 7 8 9 10
请按任意键继续. . .

性能分析:分而治之,T(N)=T(N/2)+T(N/2)+O(N) → T(N)=O(N logN);merge过程严格保证序列1小于等于序列2,使之稳定。

  • 时间复杂度:O(N logN)
  • 空间复杂度:O(N)
  • 稳定性:稳定

归并排序非递归算法:比递归算法更快速,也是稳定的

//归并排序-循环实现
//O(nlogn)  O(n)
#include<bits/stdc++.h>
using namespace std;

void merge(vector<int>& arr,vector<int>& aux,int L,int R,int RightEnd) {
	//将有序的A[L]-A[R-1]和A[R]-A[RightEnd]归并成一个有序序列
	int LeftEnd = R - 1; //左边终点位置
	int i = L;   //有序序列起始位置
	int count = RightEnd - L + 1; //本次归并元素总个数

	while (L<=LeftEnd && R<=RightEnd) {
		if (arr[L] <= arr[R])
			aux[i++] = arr[L++];  //将左边元素复制到aux
		else 
			aux[i++] = arr[R++];  //将右边元素复制到aux
	}

	while (L <= LeftEnd)
		aux[i++] = arr[L++];      //直接复制左边剩下的
	while (R <= RightEnd)         
		aux[i++] = arr[R++];      //直接复制右边剩下的

	//for (i = 0; i < count; i++,RightEnd--) //将有序序列aux复制回arr
	//	arr[RightEnd] = aux[RightEnd];       //因为两次mergePass操作使得无需这一步
}

void mergePass(vector<int>& arr,vector<int>& aux,int n,int length) {
	int i, j;
	for (i = 0; i <= n-2*length; i+=2*length) {
		merge(arr,aux,i,i+length,i+2*length-1);
	}
	if (i + length < n) //归并最后2个子列
		merge(arr, aux, i, i + length, n - 1);
	else      //最后只剩一个
		for (j = i; j < n; j++) aux[j] = arr[j];
}

void mergeSort(vector<int>& arr) {
	int n = arr.size();
	vector<int> aux(n,0);
	int length = 1;
	while (length<n) {
		mergePass(arr,aux,n,length);  //arr-->aux
		length *= 2;
		mergePass(aux,arr,n,length);  //aux-->arr
		length *= 2;
	}
}

int main() {
	vector<int> arr = { 8,6,10,7,9,4,3,2,5,1 };
	mergeSort(arr);
	for (auto x : arr) {
		cout << x << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}
1 2 3 4 5 6 7 8 9 10
请按任意键继续. . .

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值