【排序】快速排序

思想

快速排序有分治的思想

在这里插入图片描述

首先一块连续的空间为q 左端点为l 右端点为r

  1. 确定分界点

分界点可以取区间上的随机一点 例如左端点,右端点,中点
记录此时的值 例如中点就是q[ (l+r) / 2]

  1. 调整范围

将将左端点的左侧都放置成小于等于分界点的数
将右端点的右侧都放置成大于等于分界点的数
(如果要是降序排序将上述过程反转 即左侧都大于等于分界点 右侧都小于等于分界点)

  1. 递归处理左右两端

递归调用 处理分界点左侧的数据和右侧的数据

代码实现

双指针

思路

  1. 定义两个变量 i j 标记左端和右端
  2. 遍历分界点左侧的元素 当遇到大于等于分界点的元素时停下
  3. 遍历分界点右侧的元素 当遇到小于分界点的元素时停下
  4. 此时两个标记变量分别指向不属于左侧和右侧的元素(即左侧大于分界点,右侧小于分界点的元素)
  5. 交换两个标记点标记的元素 交换结束后继续遍历

在这里插入图片描述

void quick_sort(int q[], int l, int r)
{
	if (l >= r)
	{
		return;
	}
	int i = l - 1;
	int j = r + 1;
	//这里l-1和r+1的原因是在下面的循环中是do-while结构
	//所以要在左侧-1 右侧+1
	int k = q[(l + r) / 2];
	//标记点
	while (i < j)//当左右标记点相遇 说明已经全部调整结束循环
	{
		do {
			i++;
		} while (q[i] < k);//如果大于等于q[k]则停止,开始右侧循环
		do {
			j--;
		} while (q[j] > k);//找到左侧小于等于q[k]的元素
		if (i < j)//循环结束 两个标记点处的元素交换 各取所需
			swap(q[i], q[j]);
	}
	quick_sort(q, l, j);//递归处理左侧
	quick_sort(q, j + 1, r);//递归处理右侧
}

时间复杂度

先说结论
在最糟情况下,其运行时间为O(n2)。。在平均情况下,快速排序的运行时间为O(nlogn)。

最坏情况

如果你选择的数组本身就是有序且你选择第一个元素为分界点

此时你进行一次大循环后 发现分界点左侧没有元素 因为你选择的分界点就是最小的元素

在后面递归处理两侧元素时 相当于再次进行了一个(n-1)个元素的递归

即这一段的时间复杂度就是o(n);

因为每次都要遍历一遍 都要遍历一遍所有元素 就是o(n)

在最糟情况下 该算法的运行时间为O(n) * O(n) = O(n2)。

平均情况

如果选用中间元素为分界点

则每次大循环后分界点两侧的元素数量基本相同

这时在递归就将数据拆成两半 如此拆分 类似于二分查找的折半

时间复杂是O(logn)

因为每次都要遍历一遍 都要遍历一遍所有元素 就是o(n)

在平均情况下 该算法的运行时间为O(n) * O(logn)= O(nlogn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉着的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值