快速排序C/C++

快速排序

1.举个例子

首先我们给出组数据:6 1 2 7 9 3 4 5 10 8
接下来,我们的目的是将他们从小到大排序;

首先:我们设立一个基准数(也就是这组数据的第一个数,6),接下来,我们需要把比基准数6大的数全部放到6的右边比基准数6小的数全部放到6的左边(也就是将基准数放在中间某个位置使得基准数左边的数全部小于他,基准数右边的数全部大于他)

那么我们该如何实现这个过程呢?
我们可以用交换的方法,我们从右边开始,寻找一个比6小的数,再从左边寻找一个比6大的数,然后交换他们的位置
这里我们需要用到两个小可爱:ij;让他们分别从左右两端开始寻找符合要求的数
看下图

61279345108
ij

小可爱 j 开始移动(每次必须是从 j 开始!)

61279345108
ij

找到一个比6小的数了,然后就是 i 的工作了

61279345108
ij

交换!

61259347108
ij

我们发现 ij 并没有相遇,那么我们继续,我们发现9>6,4<6,果断交换!

61254397108
ij

接下来,我们的小可爱 ij 终于见到了彼此,那么我们就将 3 和 基准数6 交换,这样我们就找到了属于 6 的那个专属位置 k

31254697108
i j

到此第一轮“探测”真正结束。现在基准数6已经归位,此时以基准数6为分界点,6左边的数都小于等于6,6右边的数都大于等于6。回顾一下刚才的过程,其实哨兵 j 的使命就是要找小于基准数的数,而哨兵 i 的使命就是要找大于基准数的数,直到 ij 碰头为止。

现在我们将第一轮“探测"结束后的序列,就需要用到二分的思想。以6为分界点拆分成两个序列,左边的序列是“3 1 2 5 4”,右边的序列是“9 7 10 8”。接下来还需要分别处理这两个序列。因为6左边和右边的序列目前都还是很混乱的。不过不要紧,我们已经掌握了方法,接下来只要模拟刚才的方法分别处理6左边和右边的序列即可。现在先来处理6左边的序列现吧。

第一轮探测后,我们得到以下序列

21354

接下来我们又以 3 为分界点

12345

如此便将 6 左边的序列排好序,右边同样如此;
由此我们可以发现,每一轮排序的过程,就是将基准数归位的过程,直到将每一位基准数归位,这个过程就结束了。

接下来以《啊哈算法》里面的图示来展现:
666
在最坏的情况下,可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和
冒泡排序是一样的,都是 O(N2),它的平均时间复杂度为 O (NlogN)。其实快速排序是基于一种叫做“二分”的思想。

2.代码实现

下面是这个算法的代码实现

void quicksort(int left,int right)
{
	if(left>right)
		return ;//判断是否错误 
	int i=left,j=right; 
	int temp=a[left];//temp 用来存储基准数 
	while(i!=j)//当i,j没有相遇时 
	{
		while(a[j]>=temp&&i<j)//直到寻找到一个比基准数大的数 
			j--;
		while(a[i]<=temp&&i<j)//直到寻找到一个比基准数大的数
			i++;
		if(i<j)//必须满足i<j 
			swap(a[i],a[j]);//swap是C++中自带的,当然,C语言可以变量赋值交换 
	}
	swap(a[i],a[left]);//基准数归位 
	quicksort(left,i-1);//继续归位分界点左边的序列 
	quicksort(i+1,right);//继续归位分界点右边的序列 
	//实际上是一个递归和二分的过程 
}

假如我们输入以下数据

 10 
 6 1 2 7 9 3 4 5 10 8 

得到的结果就是

  1 2 3 4 5 6 7 8 9 10

下面就是这个序列变化的过程(带*号的是基准数)

 6 1 2 7 9 3 4 5 10 8 
 3 1 2 5 4 *6* 9 7 10 8 
 2 1 *3* 5 4 6 9 7 10 8 
 1 *2* 3 5 4 6 9 7 10 8 
 *1* 2 3 5 4 6 9 7 10 8 
 1 2 3 4 *5* 6 9 7 10 8 
 1 2 3 *4* 5 6 9 7 10 8 
 1 2 3 4 5 6 8 7 *9* 10 
 1 2 3 4 5 6 7 *8* 9 10 
 1 2 3 4 5 6 *7* 8 9 10 
 1 2 3 4 5 6 7 8 9 *10*

文末附上完整代码

#include<bits/stdc++.h>//万能头文件真香 
using namespace std;
int a[505];//这里我们定义全局变量,函数中方可调用 
int n;
void quicksort(int left,int right)
{
	if(left>right)
		return ;//判断是否错误 
	int i=left,j=right; 
	int temp=a[left];//temp 用来存储基准数 
	while(i!=j)//当i,j没有相遇时 
	{
		while(a[j]>=temp&&i<j)//直到寻找到一个比基准数大的数 
			j--;
		while(a[i]<=temp&&i<j)//直到寻找到一个比基准数大的数
			i++;
		if(i<j)//必须满足i<j 
			swap(a[i],a[j]);//swap是C++中自带的,当然,C语言可以变量赋值交换 
	}
	swap(a[i],a[left]);//基准数归位 
	quicksort(left,i-1);//继续归位分界点左边的序列 
	quicksort(i+1,right);//继续归位分界点右边的序列 
	//实际上是一个递归和二分的过程 
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	quicksort(1,n);//调用函数 
	for(int i=1;i<=n;i++)
		printf("%d ",a[i]);
	return 0;	
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

橘落京城

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

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

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

打赏作者

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

抵扣说明:

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

余额充值