最近用sort函数比较多,发现现在都不会手写快排了(丢人),这里来复习顺便尝试讲解下。这是参考《啊哈算法》上的例子写的,因为我懒得找例子了。
快排原理
快排核心是一种跳跃式的比较大小,从而时间复杂度较低。
首先我们看到这个数组
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
6 | 1 | 2 | 7 | 9 | 3 | 4 | 5 | 10 | 8 |
第一轮探测
下标从0开始,我们选取一个基准数a[0]=6,然后我们从右边界用j为下标开始找,找第一个小于基准数6的,当然是下标为7的时候的5。然后我们从左边界用i作为下标开始找,找第一个大于基准数6的数,当然是下标为3的时候的7了。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
6 | 1 | 2 | 7 | 9 | 3 | 4 | 5 | 10 | 8 |
此时我们的i还是小于j的,那么我们交换这两个地方的位置。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
6 | 1 | 2 | 5 | 9 | 3 | 4 | 7 | 10 | 8 |
然后我们继续从右边开始,与之前步骤一样的
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
6 | 1 | 2 | 5 | 9 | 3 | 4 | 7 | 10 | 8 |
继续交换位置
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
6 | 1 | 2 | 5 | 4 | 3 | 9 | 7 | 10 | 8 |
然后j继续向左寻找基准数小的数,于是j=5的位置停下来了。然后i开始向右寻找比3大的数,但是此时I与j相遇了,在 i 与 j 相遇的时候我们将基准数与此时的相遇点的数交换。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
3 | 1 | 2 | 5 | 4 | 6 | 9 | 7 | 10 | 8 |
第一轮探测已结束
大家可以看到,其实总结起来,就是
- 先找到基准数,一般我们把第一个取为基准数。
- 开始时我们将 i 指向数组最左边(0),j指向数组最右边。
- 因为这个时候设置的基准数是最左边的数,那么我们要从最右边 j 开始往左边搜索第一个比基准数小的数;然后出动 i ,从左边寻找第一个比基准数大的数,找到之后交换两者位置。
- 若 i 与 j 未相遇,那么就继续执行第三步。若 i 与 j 相遇便终止,交换基准数与相遇点。
第二轮探测
此时我们以上一轮的基准数为分界点拆成两个序列,左边的很明显我们可以知道是
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
3 | 1 | 2 | 5 | 4 |
然后我们与第一轮探测一样的,此时我们直接得出结果
0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
2 | 1 | 3 | 5 | 4 |
此时3已经归位,接下来处理3左边的序列与右边的序列。
总结
快排的思路就是将每一次的基准数归位,直到所有的数都归位,那么排序也就完成了。
两天前写的新鲜的快排模板
#include <cstdio>
#include <algorithm>
using namespace std;
int a[200010];
void quicksort(int left,int right)
{
int mid=a[(left+right)/2];
int i=left,j=right;
do
{
while(a[i]<mid)
{
i++;
}
while(a[j]>mid)
{
j--;
}
if(i<=j)
{
swap(a[i],a[j]);
i++;
j--;
}
}
while(i<=j);
if(left<j)
quicksort(left,j);
if(i<right)
quicksort(i,right);
return;
}
int main()
{
int n;
while(~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]);
}
printf("\n");
}
}
如果你觉得你快排啥的都会了,那么我们就可以学一个c++的sort函数了。
用法:
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
他初始排序是从小到大的排序,而如果要改变成从大到小的排序,就需要重写cmp函数。
然后这个sort函数还比较好用的地方在于,他可以比较结构体中元素的大小。
#include <cstdio>
#include <algorithm>
using namespace std;
struct kuailefengnan
{
int x;
int y;
}q[1100];
bool cmp(kuailefengnan a,kuailefengnan b)
{
return a.x>a.y;
}
int main()
{
for(int i=0;i<10;i++)
{
scanf("%d %d",&q[i].x,&q[i].y);
}
sort(q,q+10,cmp);
}
重写就和上面的cmp一样。
后记
这里提及sort函数是因为他是一种类似于快排的排序,如果你快排掌握熟练了,可以直接使用sort函数减少敲代码时间。