排序算法—快速排序

快速排序

快速排序是交换排序的一种,又称为划分交换排序,由C. A. R. Hoare在1960年提出。

题目描述

给出一组数据,根据由小到大顺序输出。

输入要求:

输入一个整数n(数据长度)
输入n个数据

输出要求:

输出由小到大排序后的数据

样例输入:

10
37 28 46 19 55 28 92 84 63 71

样例输出:

19 28 28 37 46 55 63 71 84 92

基本思想

假设待排序的数据都存放在数组R[n]中,取一个元素作为基准值(temp),用此基准值将无序区间划分为左右两个较小的无序区,左边的无序区数据均小于temp,右边的无序区均大于temp,而基准值temp则位于最终位置上。而对划分采取递归方式进行,即一组数据被一分为二,然后二分为四,四分为八……最后每个数据均落到最终位置上。

先来分析一次划分的过程:
先取基准元素temp=R[i],j从右开始找到第1个比temp小的元素,R[i]和R[j]交换,这样,比temp小的元素就放到了temp的前面,然后i从左开始找到第1个比temp大的元素,R[i]和R[j]交换,比temp大的元素就放到了temp的后面,如此交替进行,直到i=j时,一次划分结束,temp放入最终位置R[i]。

在这里插入图片描述

再来看递归处理的过程:
划分之后,不仅使基准temp放入最终位置,并且temp的左区间都小于temp,右区间都大于temp,即左区间元素的最终位置一定是在左区间,右区间元素的最终位置一定在右区间。所以对划分后的左右区间进行同样的划分处理,这样不断的划分过程中,处理的区间越来越小,元素越来越少,速度也就越来越快。

在这里插入图片描述

快速排序的处理过程与直接插入排序、希尔排序、冒泡排序、直接选择排序等有些不同,这几个排序有的插入,有的交换,但基本都是想办法将元素放入到有序区间内,然后有序区间不断扩大,直到所有元素都放入有序区间,最终形成有序序列。快速排序每次直接将基准元素定位到最终位置,在排序过程中没有有序区间,直到排序结束才形成有序序列。从逻辑上来看其他那几个排序,都像是从头至尾扩充,而快速排序有点像是从中间向外扩散。

参考代码(C语言)
#include<stdio.h>
void quick_sort(int R[],int s,int t); //快速排序 
int partitioon(int R[],int s,int t); //划分 

int main()
{
	int i,R[100],n;
	scanf("%d",&n);	
	for(i=0;i<n;i++)
 	scanf("%d",&R[i]);
 	quick_sort(R,0,n);
 	for(i=0;i<n;i++)
 	printf("%d ",R[i]);
	return 0;
} 

int partitioon(int R[],int s,int t)	//对区间进行划分
{
 	int i,j,temp;
 	i=s;
 	j=t;
 	temp=R[i];	//temp为基准
 	do{
  		while((R[j]>=temp)&&(i<j))	
  			j--;			//j向右扫描,找到比temp小的元素
  		if(i<j)	 R[i++]=R[j];		//交换R[i]和R[j]
 		while((R[i]<=temp)&&(i<j))
  			i++;			//i向左扫描,找到比temp大的元素
  		if(i<j)  R[j--]=R[i];		//交换R[i]和R[j]
 	}while(i!=j);
 	R[i]=temp;	//temp确定最终位置
 	return i;	//返回temp的最终位置i
}

void quick_sort(int R[],int s,int t)
{
 	int i;
 	if(s<t)		//只有1个元素或无元素时不需排序
 	{
  		i=partitioon(R,s,t);	//对R进行划分
  		quick_sort(R,s,i-1);	//递归处理左区间
  		quick_sort(R,i+1,t);	//递归处理右区间
 	}
}
分析总结

平均时间复杂度O( n l o g 2 n nlog _2n nlog2n)
空间复杂度O( l o g 2 n log _2n log2n)

快速排序和起泡排序均属于交换排序,起泡排序中一次交换只能移动一个位置,效率相对较低,快速排序则克服了这种缺点,每次交换都把相应元素划入自己应该在的区间,然后通过缩小区间定位元素最终位置。

可以看出快速排序是目前基于比较的内部排序方法中最快的,故因此得名。快速排序在考试、竞赛、面试等地方考察的也很多,所以十分受重视,它的思想可以算作分治算法的思想,就是将大问题分解为若干子问题,子问题依旧具有大问题的性质,然后将子问题的结果汇总,得到大问题的结果。这种思想在解决很多计算机实际问题时也都会涉及。

快速排序是不稳定的。在本例中,虽然最后两个28的相对顺序没变化,但是在第一趟划分结束后,两个28的相对位置发生了变化,就说明排序有不稳定的风险,只是恰好之后的排序中,28的位置又发生了改变而已。可以验证序列28 28’ 19,第一趟划分,28为基准,28与19发生交换,排序结果为19 28’ 28,两个28的相对顺序发生了变化。

写在最后

代码的表达形式多种多样,重点是理解排序的思想和过程,附上一个网上看到的动画,可以帮助理解排序过程☛链接在此(个人觉得如果有一些基础的看本文上面给的图示去理解最好,更有助于建立编程的思维,视频能相对有些趣味性)
说明: 链接内视频不是本人制作,如侵权则删。当然网上的视频有很多,我只是找了一个相对简单明了的,大家也可自行搜索。

参考资料:《数据结构-用C语言描述》高等教育出版社

(只是分享个人学习时的想法和理解,如有问题还望大佬指点)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

#include编程小黑

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

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

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

打赏作者

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

抵扣说明:

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

余额充值