#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstdlib>
using namespace std;
//快速排序
/*
原理:取基准,比基准数小的放在左边,比基准数大的放在右边,递归
另外,关于下文中提出的几个问题,在后面的手动推演中给出了答案
*/
int a[9]={0,1,54,77,77,97,32,8,21};
int t[9];
void fun(int l,int r)
{
if(l>=r) return; //一开始给出递归停止的条件(l==r的条件是终止不了的,这是因为每次函数fun处理完以后l,p自增或者自减的缘故,当然也有可能l==r作为终止条件)
int mid=a[(rand()%(r-l+1))+l];
int p=l,q=r; //一般传进来的参量l,r不要动,引入别的变量代替l,r进行后面需要改动的操作
//原数组中不好操作时,及时引入辅助数组t
/*
如果采用左右同时扫描,坐标找到一个比mid大的,右边找到一个比mid小的两者交换的思路的话,
会发现不太好搞,因为左右这样符合条件的数不一定成对。
所以思路上采用:扫描原来的整个数组,碰到比mid小的,从左边放入辅助数组t,碰到比mid大的,
从右边放入辅助数组t。
*/
for(int i=l;i<=r;i++) //开始扫描
{
if(a[i]<mid) //按顺序放入t数组,这里不能取a[i]<=mid,,必须把等于mid的情况放在下一个for循环中,否则递归不完
t[p++]=a[i];
if(a[i]>mid)
t[q--]=a[i];
}
for(int i=p;i<=q;i++) //剩下的都和mid一样大(这里p和q都取=的原因在于上一步中p,q的后置运算符)
t[i]=mid;
for(int i=l;i<=r;i++)//就从功能单元的角度理解,这一步是不能少的(不要从一次次的递归嵌套理解)
a[i]=t[i];
fun(l,p-1); //p-1说明中间那一部分和mid一样大的元素不用管了
fun(q+1,r);
/* 无论基准值是不是随机的,p-1和q+1都不能变,否则递归结束不了。因为如果不管p,q的后置运算符,那么那么在下一次的递归中,开辟的数组范围就会变*/
}
int main()
{
fun(1,8);
for(int i=1;i<=8;i++)
cout<<a[i]<<" ";
return 0;
}
另外补充一点:mid之所以取随机值是为了降低复杂度,达到O(nlogn)