快速排序---递归下的排序

记录一下两个跟分治比较相关的排序---归并排序和快速排序,两种排序都采用分而治之的思想,将一个问题分为连个子问题,先解决局部有序,然后实现整体有序,两种方法有着比较多的共同之处,平均复杂度都在Onlogn,是比较高效的排序方法。

快速排序 quick_sort()

思路

快速排序会选择一个标准点key(下面都这样称呼),然后将所有比他小的移动到左边,所有比他大的移动到他的右边,那么这时候,只要左边区间实现了有序,右边区间也实现了有序,那么整体就是有序的了。

就用升序排序举个最简单的栗子:

这是第一轮时候的样子,一般情况下我们会就把第一个作为我们的key,这里也就是i所对应的2,然后我们会先从j开始搜索(后面会解释一下为什么一定要从j开始,不能从i开始),我们的目标是需要找到一个比2小的,于是就会变成这样

 可以看到1要比2小,于是停下了,这时候i开始向右寻找,找到了4比2大,于是也停下了,

这时候把i和就所对应的数字交换

 然后继续第二轮寻找,这时候在j找完之后就会变成这样

 发现j和i一样了,这时候就表明探测已经结束了,这时候左边第二个(除去key点)到i一定都是比key小的,后面都是比key大的,然后再把key点2与ij所在的点交换,这一轮探测就结束了,

可以看到序列有序了。

这个其实就是一个问题的比较简单的一个子问题,解决了所有这样的子问题之后,其实整个序列也就有序了。

那么子问题反映在程序中其实就是递归的使用,这里我们把key值换到了ij位置,i和j相同的,左边都比key小,右边都比key大,所以只要key值(ij位置)的左边和右边都有序,那么整体就是有序的,也就是对左边和右边再使用queck_sort()。

下面讨论一下开始为什么要强调一定要从j开始探测,我一定要从i开始不行吗?还真不可以,来看一下下面这个栗子:

就像上面这种情况,这时候你如果从i开始探测,那么找到第一个比3大的,一定是4,这时候ij相同,探测结束了,把3和4交换,

这时候你一看,啥呀这完全没有实现我们预期的目标,4最大反而到了第一个。

那么为什么会这样?主要就是因为要想最后让key点归位,这时候你需要ij位置的数和key换位置,我们选择了最左边的位置为key,那么也就是把一个比key小的换过来(左边的数字都小于key),但是你如果用i先去找,那么不可避免这时候i会找到后面比他大的,这时候撞上j,就结束探测了,这时候i就会停在比key大的位置(上图),也就导致最终把一个比key大的换到了左边,当然也就错了。但是j先找,就不会,因为j一定是找到比key小或者i才会停,不会影响最终的结果。如果是右边为key反一反就好。

贴一个gif

下面推荐一个博文,感觉讲的很不错

快速排序(详细讲解)_梦里Coding的博客-CSDN博客_快速排序

最后快速排序之所以叫做快速排序,不仅因为其复杂度低,同时因为其写法中都是while这样的循环,执行速度也很快,是最常用的排序方法之一(似乎c++的sort函数就是快排?)。

有时间写一下归并排序。

参考代码

#include<stdio.h>
int a[] = { 0,1,5,7,4,2,3,6,6,7,5,3,2,6,0,1,1,1,9,2,1,1,8,9,3,2,1 };
int n = sizeof(a) / sizeof(a[0]) - 1;

void print() {
	for (int i = 1; i <= n; i++)
		printf("%d ", a[i]);
	printf("\n");
}

void swap(int i, int j) {
	int x = a[i];
	a[i] = a[j];
	a[j] = x;
}

//quick_sort()
void quick_sort(int l, int r) {
	if (l<1 || r>n || l > r)return;//无效
	if (l == r)return;//已经有序
	//if (r - l == 1) {//两个的情况应该时不需要判断的
	//	if (a[l] > a[r])swap(l, r);
	//	return;
	//}
	int x = a[l];
	//左边第一个为基准点,那么必须要j先出发
	int i = l, j = r;
	while (i < j) {
		while (a[j] >= x && i < j)j--;
		while (a[i] <= x && j > i)i++;
		swap(i, j);
	}
	swap(i, l);//结束探测,枢轴归位
	quick_sort(l, i - 1);
	quick_sort(j + 1, r);//继续排序
}

int main()
{
	printf("排序前:");
	print();
	quick_sort(1,n);
	printf("排序后:");
	print();
	return 0;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值