排序实现与分析 -- 快排

快速排序

描述

快速排序,是一个很重要的排序算法,当然其平均性能也比较高,他的思想我借鉴纪磊在啊哈算法中的形容来描述。
在这里插入图片描述

在快排中,我们把待排序数据(如上图)中的第一个数据拿出来,称他为基准,就是拿接下来的数字都跟他进行比较,如下图所示,我们假设有两个炮兵(此处红五角星标识),一个在数据的最左边,一个在数据的最右边,刚开始我们右炮兵拿起他的数字7跟基准比,此数字大于基准6,所以炮兵往前走,9大于6,再往前走,3小于6,找到第一个小于基准6的数字,把3放到基准原位置,然后左炮兵往后找,5、4、1、2小于6,炮兵一直往后走,直到两个炮兵相遇,说明数据全部走完,所以基准数字找到了他的位置,就放到现在炮兵的位置,此时,6左边的数字全部小于6,右边的全部大于6,一次分割结束。
在这里插入图片描述
然后就是左边数字后右边数字分别再次进行分割,直到所有组内只剩一个数组代表排序结束。
后续过程不做详细说明


代码实现

此代码实现是通过递归实现,我们把分割,调用分割的递归,分开实现,炮兵我们分别用low,high来标识,基准保存在tmp变量中
一次划分

//函数返回基准最终位置的下标,为下次划分做准备
int Partition(int *arr,int low,int high)//
{
	
	int tmp = arr[low];//去除基准
	
	while(low < high)//两炮兵没相遇
	{
		while(arr[high] >= tmp && low < high)//右炮兵往前走,遇到小于基准的数字跳出,因为是循环,以防在此循环中炮兵提前错过
		{
			high --;
		}
		if(arr[high] < tmp)//如果是找到小于基准的数字而跳出,将此数字放入原基准位置(其实说是上一个空位比较恰当)
		{
			arr[low] = arr[high];
		}
		while(arr[low] <= tmp && low < high)//左炮兵往后走,遇到大于基准的数字,跳出,同时判断炮兵是否错过
		{
			low ++;
		}
		if(arr[low] > tmp)//找到比基准大的数字,放入空位
		{
			arr[high] = arr[low];
		}
	}
	arr[low] = tmp;//最终的空位将基准放入
	return low;//返回基准的位置
}

快排

void quick(int *arr,int low,int high)//O(logn),O(logn)
{
	int par = Partition(arr,low,high);//接收返回划分点

	//进行递归
	if(low + 1 < par)//若是左边组内数字超过一个继续划分
	{
		quick(arr,low,par - 1);//新的边界为左边至划分点
	}
	else if(par + 1 < high)//判断组内数据个数
	{
		quick(arr,par + 1,high);//新的边界为划分点至右边
	}
}
时间复杂度、空间复杂度及稳定性
  1. 这里我们一次划分的时间复杂度是O(n),虽然是三层循环嵌套,但是实则遍历了一遍数据,然后递归要进行logn次递归(本文log均为以二为底),所以快排的时间复杂度为O(n*logn)
  2. 这里一次划分的空间复杂度为O(1),递归调用logn次,所以快排的空间复杂度为O(logn)
  3. 因为出现跳跃式交换数据,所以并不稳定

进一步分析

当待排序数据完全有序,拿出第一个数据作为基准,从后往前全部遍历,每次都要如此,快排时间复杂度退化为O(n^2),并且退化为选择排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值