排序算法——快速排序

本文深入解析了快速排序算法的基本原理及其实现过程,介绍了通过递归方式选取基准数,并将数组分为左右两部分,使得左边元素均小于基准数,右边元素均大于基准数,最终达到全局有序的状态。同时,分析了快速排序的时间复杂度和空间复杂度。
摘要由CSDN通过智能技术生成

快速排序


基本做法

在此我们使用递归的快速排序。既然使用了递归,自然就是要解决一些重复的子任务,然后完成最后的大任务,而大任务自然就是让整个数组整体有序,那需要重复的小任务是什么呢?

快排的一个个子任务,就是要在各自范围内的数组中取一个数当基准数(一般取范围内的最左边、最右边或中间的数),然后让其它的数小于基准数的放左边,大于基准数的放右边,这就是快速排序递归的子任务。

整体的实现则是先对【1,n】范围内的数开始任务,任务完成后,基准数已经在中间,再对【1, 基准数的位置-1】和【 基准数的位置+1,n】开始任务,也就是对基准数左边的范围和右边的范围开始任务,而开始任务其实就是进入下一个递归了。最后所有的递归完成后,也就说明所有范围内的数都已经实现了左边的数小于当前范围的基准数,而右边的数也已经全部大于当前范围的基准数,自然数组整体已经是有序的了。不太理解为什么,可以自己画一下图,每次就取最左边的数作为基准数。

代码构造

首先我们取范围内最左边的数做为基准数,然后让ij分别指向最左边和最右边的位置,再是开始循环。循环的条件需要是i < j,然后因为我们取的是最左边的数,所以我们需要从右边开始向左查找比基准数要小的数,至于为什么取最左边就要从右边开始查找,这是为了之后基准数归位时,i所指向位置的数必定是小于基准数的,这样让基准数跟i所在位置的数进行交换,不会影响任务的完成。查找到比基准数小的数之后停止循环,再开始从左边往右开始查找比基准数大的数,查到之后停止循环。然后交换两个查找到的数,即把比基准数大的数放到右边,比基准数小的数放在左边,再是开始下个查找,直到i >= j。如果期间遇到查找不到的情况,完全没有问题,因为你会发现,最终i指向的值必定小于基准数,而i下一个位置的数要么没有数,要么就是比基准数大的数,最后把基准数和i所指向的数进行交换,任务就完成了。接着就开始基准数左边和右边的子任务,任务流程是一样的。

class Solution {
public:
	Solution() {}
	~Solution() {}
	void quickSort(vector<int>& nums, int left, int right) {
		if (left >= right) {
			return;
		}
		int tmp = nums[left];
		int i = left, j = right;
		while (i < j) {
			while (i < j && nums[j] >= tmp) {
				j--;
			}
			while (i < j && nums[i] <= tmp) {
				i++;
			}
			if (i < j) {
				swap(nums[i], nums[j]);
			}
		}
		nums[left] = nums[i];
		nums[i] = tmp;

		quickSort(nums, left, i - 1);
		quickSort(nums, i + 1, right);
	}
	
	vector<int> sortArray(vector<int>& nums) {
		int len = nums.size();
		quickSort(nums, 0, len - 1);
		return nums;
	}
};

时间复杂度

平均情况最好情况最坏情况
O ( N l o g 2 N ) O(Nlog{_2N}) O(Nlog2N) O ( N l o g 2 N ) O(Nlog{_2N}) O(Nlog2N) O ( N 2 ) O(N^2) O(N2)

空间复杂度

辅助存储
O ( N l o g 2 N ) O(Nlog{_2N}) O(Nlog2N)

稳定性

不稳定,快速排序在排序的时候,会把相同关键字的顺序打乱,就是本来在前面出现的数可能会被放到后面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值