作者:学到牛牛龚晓潺
在对于刚接触编程这个领域的同学,对排序还没有一定的了解的时候,就光是听到快速排序这个名称就会觉得很有吸引力,这个名字取得粗鲁且自信,让人不得不想去了解一下他自信的来源
快速排序其实是对冒泡排序的一种改进,名字里面的快速两个字得确也有自信的实力,它相对于其他几种排序来说效率较高,速度更快,但对于初学者而言,快速排序还是很难理解的,因为快速排序的一些特殊性,现在很多公司也会去选择它作为面试的考题,如果仅仅是依靠背代码,默写的方式的话估计很难去把快速排序写好,所以我们这个时候就得知道思路的一个重要性,只有把它的思想理解到位,我们才能更快的把快速排序学会。
首先,我们先来看一下快速排序的一个概念
快速排序是指通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行之前的操作,以此达到整个数据变成有序序列。
我们根据它的概念来详细看一下快速排序的思路
第一步如图1-1所示,先得去找一个基准数,一般来说数组第一个为基准数,现在可以理解为数组第一个数赋值给了key,成为基准数,数组的第一个位置产生了空缺(有位置没人坐)
intkey=a[i];
再去找到一个最左边的下标,一个最右边的下标(其实就是长度减一)
intleft=0,intright=6;
图1-1
因为左右两个下标是不会变动的,所以后期为了我们数组左右两边的数能够和基准数更好的进行比对,我们再去定义两个下标i,j分别等于left,right(如图1-2所示)
inti=left,j=right;
i和j就会一个从左边进行比较,一个从右边进行比较,记录每次比较之后的下标
图1-2
接下来从右边第一个数开始和基准数对比,该数如果大于基准数的话(a[j]key),它的位置则不变,继续下一个数的对比(j--),如果小于基准数的话(a[j]key),就结束右边的对比,该数就放到空缺的位置上面去(a[i]=a[j]),新的空缺位产生(如图1-3所示)
while((a[j]key))
{
j--;
}
a[i]=a[j];
图1-3
接下来再从左边的数开始和基准数对比,如果该数比基准数小(a[i]key),则位置保持不变,继续下一个数的对比(i++),如果比基准数大(a[i]key)则结束左边的对比,该数移到空缺位(a[j]=a[i]),新的空缺位产生(如图1-4所示)
while((a[i]key))
{
i++;
}
a[j]=a[i];
图1-4
继续从右边上一次的位置进行之前相同的操作(如图1-5所示)
图1-5
现在就回到了左边,我们可以清晰的看到i和j已经相遇了那这个时候第一次对比结束,将基准数放回最后的空缺位置,a[i]=key;
第一次快排结束(如图1-6所示)
这时候聪明的同学就会发现一个隐藏条件,也是循环的退出条件ij
图1-6
(若出稿请在素材中更换此图,删除本句话)
第一次快排结束之后整个排序并没有结束,接下来我们通过递归继续剩下来的对比,由之前这个基准数为界,划分为左右两部分,两部分同时进行第一次快排相同的步骤,直到全部比较完变成一个有序的数组
sort(a,left,i-1);
sort(a,i+1,right);
以上呢,是数组实现快速排序的基本步骤,一些重点的代码部分也写了出来,为的就是让同学们学会将思想转化为代码
那接下来我们来一起看看快速排序的完整代码
#includestdio.h
voidsort(inta[],intleft,intright)
{
inti=left,j=right;
intkey=a[i];
if(left=right)//左边始终要小于我们的右边,如果等于结束整个程序
return;
while(ij)//每次快排退出条件
{
while((ij)(a[j]key))
{
j--;
}
a[i]=a[j];
while((ij)(a[i]key))//这里的ij防止上面的j减过头导致程序出现错误
{
i++;
}
a[j]=a[i];
}
a[i]=key;
sort(a,left,i-1);//递归将数组分成两部分同时进行快排
sort(a,i+1,right);//i就是第一次快排相遇的下标位置
}
intmain()
{
inti;
inta[]={2,1,5,4,6,3};
intlen=sizeof(a)/sizeof(a[0]);
sort(a,0,len-1);//传参,left=0,right=长度-1
for(i=0;ilen;i++)
{
printf("%d",a[i]);
}
printf("\n");
return0;
}