快速排序的大致思路
通过找出一个基准数,然后从左向右,从右向左依次找出比这个基准数大(小)的数字,然后交换它俩,
最后将基准数与每轮判断的结尾处交换,
这样每轮结束后,刚刚排序的部分都会被分成两部分,在基准数左边的数字都比基准数小,在基准数右边的数字都比基准数大,
然后不断二分下去,最后整体排序完成 ,此方法主要运用了递归与二分
好像貌似说的有点抽象
时间复杂度
快速排序的最差时间复杂度是O(n2)
它的平均时间复杂度为O(nlogn)
下面来段正确代码
#include<stdio.h>
int n,a[100000]; //定义为全局变量在要用时就比较方便
void quicksort(int left,int right)//传参每次传进来左边与右边的边界值即可
{
int temp,i,j,flag;
if(left>right)
return;
temp=a[left]; //每次的temp中存入的就是基准数
i=left;
j=right;
while(i!=j) //当i==j时,说明关于基准数的左右两边已经判断完了
{
while(a[j]>=temp&&i<j) //当a[j]大于基准数时,就跳过它
j--;//当a[j]小于基准数时,就退出循环,
//确定了右边需要交换的位置
while(a[i]<=temp&&i<j)//当a[j]小于基准数时,就跳过它
i++;//当a[j]大于基准数时,就退出循环,
//确定左边需要交换的位置
if(i<j) //确定是基准数的左右边
{
flag=a[i];
a[i]=a[j];
a[j]=flag;
}
}
a[left]=a[i]; //将基准数归位,此时基准数左边的比基准数小
//基准数右边的,比基准数大
a[i]=temp;
quicksort(left,i-1); //递归,不断处理基准数左边的部分
quicksort(i+1,right); //递归,不断处理基准数右边的部分
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n);
for(i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
好的,现在到了最爱的举个栗子环节
比如,现在有5个数{5,1,2,7,8}
输入之后开始调用函数环节,
第一次传入的left为1,right为5
函数确定了它第一次的基准数为5,
开始寻找了,
j=5,a[5]=8,大于基准数,所以j–,
a[4]=7,大于基准数,j–,
a[3]=2,小于基准数,对于j的循环处理退出,
开始i的处理,
i=1,a[1]=5,就是基准数,所以跳过,i++,
a[2]=1,小于基准数i++,
i=3,此时i==j了,退出对i的循环处理,
判断一下i和j的大小,如果i<j,那么就交换两个数的位置,因为还没到两个循环点碰头的位置,如果i= =j,说明那么此时i和j就碰头了,这一次的基准数左右交换也就停止了
将基准数与i,j碰头的地方交换
此时的数列变成了{2,1,5,7,8}
然后开始进入函数中的函数(磨人递归)
传参为left=1,right=i-1=2;
left<right,开始循环判断,
选择a[1]为基准数,
j=2,a[2]=1,小于基准数,退出j判断循环,
i=1,a[1]=2,为基准数,i++
i=2,i= =j,退出i判断循环
因为i= =j,所以不交换,进入基准数与碰头数的交换环节
此时数组为{1,2,5,7,8}
虽然排序已经成功,但程序还没完成
具体递归且二分环节。。。我们暂且略过,递归磨人,不要深究
emmm但大概还是要理解一下的,因为每次进入函数时,都是传入左边值和右边值,然后找出基准数,对左右边界值内部的数与基准数不断比较与交换,然后再进入函数中的函数,再将刚刚的部分继续拆分,直到left>=right再返回上一层函数,然后进入后半段的比较交换,然后成功后函数再拆分再比较,再交换,直至所有的数被排序好,再一层一层退出循环,然后得到已经排好序的数列
最后的最后要附上我的错误代码,关于我的易错点
#include<stdio.h>
int n,a[100000];
int quicksort(int left,int right)//错处
{
int temp,i,j,flag;
if(left>right)
return;
temp=a[left];
i=left;
j=right;
while(i!=j)
{
while(a[j]>=temp&&i<j)
j--;
while(a[i]<=temp&&i<j)
i++;
if(i<j)
{
flag=a[i];
a[i]=a[j];
a[j]=flag;
}
}
a[left]=a[i];
a[i]=temp;
quicksort(left,i-1);
quicksort(i+1,right);
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n);
for(i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
关于这个错处,因为这个函数是没有返回值的,函数排序的过程已经对数组进行了更改,所以函数类型用void,不要顺手int
再来增加一点,就是搜索i,j的位置交换时,一定要从j(基准数的对立面)查起,不要先查i,因为从i查起,i 停留的位置一定比基准数大,然后判断j,j与i相遇时(记此点为交换点),交换点的数一定大于基准数,这样比基准数大的数最后就会被交换到基准数的左边