排序算法总结对比

/*
常用排序算法分析
*/
void	swap(int& x,int& y)
{
	if(x != y){
		x = x + y;
		y = x - y;
		x = x - y;
	}
}
/*
冒泡排序
时间复杂度为o(n^2)
两两比较,交换,每次内层循环在未排序序列中找出最大值放到已排序中
对于部分有序的序列来说,效率较高
稳定
*/
void	bubble_sort(int* arr,int start,int end)
{
	if(arr == nullptr || start <0 || start >= end)
		return;
	int pos = -1;
	for(int i = start; i <= end; i++){
		pos = -1;
		for(int j = start; j <= start + end - i - 1; j++){
			if(arr[j] > arr[j + 1]){
				swap(arr[j],arr[j + 1]);
				pos = j;
			}
		}
		if(pos != -1){//在pos后面的都是已经排序好的了
			i = end - pos - 1;
		}else{//没有经过交换,说明已经是有序的了
			break;
		}
	}
}

/*
选择排序
o(n^2)
在未排序序列中查找最大或最小值,放在已排序序列的尾部或头部
不稳定
*/
void	select_sort(int* arr,int start,int end)
{
	if(arr == nullptr || start < 0 || start >= end)
		return;
	for(int i = start; i <= end; i++){
		int maxNumPos = start;
		for(int j = start; j <= start + end - i; j++){
			if(arr[maxNumPos] < arr[j]){
				maxNumPos = j;
			}
		}
		swap(arr[maxNumPos],arr[start + end - i]);
	}
}

/*
插入排序
o(n^2)
从未排序序列中取一个数值插入已排序序列中对应位置
稳定
*/
void	insert_sort(int* arr,int start,int end)
{
	if(arr == nullptr || start < 0 || start >= end)
		return;
	int pos = 0;
	for(int i = start + 1; i <= end; i++){
		int num = arr[i];
		pos = i;
		for(int j = i - 1; j >= start; j--){
			if(num < arr[j]){
				arr[j + 1] = arr[j];	//移动
				pos = j;
			}
		}
		arr[pos] = num;
	}
}

/*
快速排序
nlog(n)
分治法
不稳定
*/

void	quick_sort(int* arr,int left,int right)
{
	if(left >= right)
		return;
	int dw = left;
	int up = right;
	int key = arr[dw];
	
	while(dw < up)
	{
		while(dw < up && key <= arr[up])
			--up;
		arr[dw] = arr[up];
		while(dw < up && key >= arr[dw])
			++dw;
		arr[up] = arr[dw];
	}
	arr[dw] = key;
	quick_sort(arr,left,dw - 1);
	quick_sort(arr,dw + 1,right);
}

/*
桶排序
o(n)
需要使用辅助空间,在集合范围较小的情况下推荐使用,效率很高
稳定
*/
void	bucket_sort(int* bucket,int* arr,int start,int end)
{
	if(bucket == nullptr || arr == nullptr || start < 0 || start >= end)
		return;
	//先找到最大值和最小值(也就是范围)
	int maxNum = arr[start];
	int minNum = arr[start];
	for(int i = start; i <= end; i++){
		if(maxNum < arr[i]){
			maxNum = arr[i];
		}
		if(minNum > arr[i]){
			minNum = arr[i];
		}
	}

	for(int i = start; i <= end; i++){
		++bucket[arr[i] - minNum];
	}
	int ncount = start;
	for(int i = 0; i <= MAX_LENGTH; i++){
		while(bucket[i] > 0){
			arr[ncount++] = i + minNum;
			--bucket[i];
		}
		if(ncount > end)
			break;
	}
}

/*
归并排序
nlog(n)
需要辅助空间
稳定
*/
void	merge_cal(int* total,int* arr,int start,int end)
{
	//bucket全局数组,长度为100000,
	//若使用堆空间,堆空间的申请和释放耗时较大,会影响算法效率的真实性
	int mid = start + ((end - start) >> 1);
	int firstStart = start;
	int firstEnd = mid;
	int secondStart = mid + 1;
	int secondEnd = end;
	int ncount = 0;
	while(firstStart <= firstEnd && secondStart <= secondEnd)
	{
		if(arr[firstStart] < arr[secondStart]){
			total[ncount++] = arr[firstStart++];
		}else{
			total[ncount++] = arr[secondStart++];
		}
	}
	while(firstStart <= firstEnd)
	{
		total[ncount++] = arr[firstStart++];
	}
	while(secondStart <= secondEnd)
	{
		total[ncount++] = arr[secondStart++];
	}
	for(int i = 0; i < ncount; i++){
		arr[start + i] = total[i];
	}
}
void	merge_sort(int* total,int* arr,int start,int end)
{
	if(total == nullptr || arr == nullptr || start < 0 || start >= end)
		return;
	int mid = start + ((end - start) >> 1);
	merge_sort(total,arr,start,mid);		//分块
	merge_sort(total,arr,mid + 1,end);
	merge_cal(total,arr,start,end);		//合并
}

之前认为冒泡与插入选择的时间复杂度都是o(n^2),所以以为使用哪一种都是一样的,但是通过对比发现,冒泡排序是最慢的一种。

横坐标为随机数据量,纵坐标为排序时间ms

从图中看出冒泡排序是最慢的,插入和选择所用的时间差不多,快速排序在这点数据量面前所用时间几乎为0.下面是具体数据。

 

在将快速排序,归并排序,和桶排序一起比较

可以看出,桶排序的时间复杂度几乎为0,快速排序与归并排序差不多,但是快速排序比归并排序要快一些,造成这样的原因可能是因为,快速排序是在原数据上直接修改,而归并排序不是且需要一次拷贝。下面是具体数据,

从上面对比可以看出,如果只论时间复杂度来说一定是桶排序获胜,如果论时间与空间复杂度还是快速排序更胜一筹。

但是快速排序是不稳定的,而桶排序与归并排序是稳定的。桶排序所耗空间复杂度取决于数据的范围而非数据量,适用于数据范围较小的排序,比如1000万学生的成绩排序。而归并排序所耗空间复杂度为o(n)与数据量相关。所以在使用还是要考虑场景和需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值