快速排序
快速排序是交换排序的一种,又称为划分交换排序,由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语言描述》高等教育出版社
(只是分享个人学习时的想法和理解,如有问题还望大佬指点)