前言
快速排序是基于分治策略的一个排序算法,时间复杂度为 O(N∗logN) ,故效率较高,也因此被广泛使用。
快速排序的基本思想
快速排序分为三步:
(1)分解:选取一个基准,使得该基准左边的数都小于它,右边的数都大于它!
(2)递归求解:在次对该基准的左右两边递归进行步骤(1)的操作,知道最后只剩下一个元素
(3)合并:逐步将选取的基准与左右两边已经排序好的数列进行合并。
图形解析
我们以如下数据进行算法分析:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
33 | 43 | 88 | 36 | 8 | 60 | 15 |
第一步进行分解,选取基准a[0]=33 i=0 j=6
- 从右往左扫描,遇到比基准小的则交换
我们找到15比33小,交换后为:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
15 | 43 | 88 | 36 | 8 | 60 | 33 |
此时,i=1 j=6
- 从左往右扫描,遇到比基准大的则交换
我们找到43比33大,交换后为:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
15 | 33 | 88 | 36 | 8 | 60 | 43 |
此时,i=1 j=5
- 从右往左扫描,遇到比基准小的则交换
我们找到8比33小,交换后为:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
15 | 8 | 88 | 36 | 33 | 60 | 43 |
此时,i=2 j=5
- 从左往右扫描,遇到比基准大的则交换
我们找到88比33大,交换后为:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
15 | 8 | 33 | 36 | 88 | 60 | 43 |
此时,i=2 j=3
- 从右往左扫描,遇到比基准小的则交换
最后当j==i==2
的时候,说明第一遍排序完成,最终结果:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
15 | 8 | 33 | 36 | 88 | 60 | 43 |
下面就是递归的用上面的算法对基准左右数组进行上叙步骤,就可以得到一个从小到大排序好的数组。
算法描述
在编写算法的时候,我们可以考虑优化上面图解:
因为基准是不变的,而且每次都是在与基准进行交换,并且最后总是a[i]==a[j]==基准
故,我们可以将基准单独存放,最后一次填充即可,无需做很多次的交换!
#include<stdio.h>
#include<string.h>
void quickSort(int a[], int i, int j) { //i 是左边游标 j是右边游标
if(i<j) {
int l=i,r=j,base=a[l]; //设置左边游标位置 右边游标位置 以及基准
while(l<r) {
while(a[r]>base&&r>l) { //从右往左扫描
r--;
}
//找到右边一个比基准小的
if(l<r) { //判断是否j>i
a[l++]=a[r];
}
while(a[l]<base&&r>l) { //接下来,从左往右扫描
l++;
}
//找到左边一个比基准大的
if(l<r) { //判断是否i<j
a[r--]=a[l];
}
}
//扫描完成 ,填充基准 此时 l==r
a[l]=base;
//依次对左右调用上面的算法
quickSort(a,i,l-1);
quickSort(a,l+1,j);
}
}
int main() {
int a[100];
int n;
printf("请输入数组大小:");
scanf("%d",&n);
for(int i=0; i<n; i++) {
scanf("%d",&a[i]);
}
quickSort(a,0,n-1);
for(int i=0; i><n; i++) {
printf("%d ",a[i]);
}
putchar('\n');
}
最后
OJ链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2020
杭电OJ的这一题只是做了一点点小小的变形!