准备好心情,让我们一起出发吧~ 假设我们对“6,1,2,7,9,3,4,5,10,8”这十个数进行排序(从小到大进行排序)。
首先我们需要随便找一个基准数(一个用来参照的数),一般情况下选取第一个数作为基准数,接下来,需要把这个序列中所有比基准数大的数放在它的右边,比基准数小的数放在它的左边。
//初始状态下,数字6在序列的第一位,我们要做的第一步就是把6挪到序列中间的某个位置,假设这个位置是k,以k为分界点,左边的数都小于等于6,右边的书都大于等于6.
类似于冒泡排序,快排也是通过交换的方式把数放到它应该在的位置。
方法很简单,分别从序列“6,1,2,7,9,3,4,5,10,8”两端开始探测。
先从右往左找一个小于6的数,再从左往右找一个大于6的数,然后交换他们。
这里可以用两个变量i,j,左边的为“哨兵i”,右边的为“哨兵j”。
刚开始时让“哨兵i”站在序列最左边一个数的位置,指向数字6,让“哨兵j”站在序列最左边一个数的位置,指向数字8,如图所示。
“哨兵j”先出发,并向左一步步移动(j - -),当找到一个小于6的数便会停下来。
“哨兵i”后出发,并一步步向右移动(i + +),直到找到一个大于6的数,然后停止。最终“哨兵j”站在了数字5的位置,“哨兵i”站在了数字7的位置。
到此,第一次交换结束。接下来“哨兵j”继续向左移动(每次必须是“哨兵j“先移动)。
然后它找到了4,并停止了下来;“哨兵i”继续向右移动,找到了9,并停了下来。再次交换4和9。
交换后如下。。。。。
当进行了多次上述操作后,便会出现哨兵相遇的情况。
此时探测结束,接下来我们需要将基准数6和他们相遇的位置所指向的数3进行交换。
至此第一轮探测真正结束,此时基准数6已经到达了属于它的位置(是不是很奇妙呢),6左边的数都小于6,右边的数都大于6。回顾一下刚才的过程,“哨兵j”的任务就是从右边开始找到小于基准数的数,“哨兵i”的任务就是从左边开始找到大于基准数的数,直接相遇。。。。。。
到此,原理应该很清楚了吧。接下来,还需要进一步操作,即以6为分界点将这个大的序列拆成两个子序列,左边的序列是“3,1,2,5,4”,右边为“9,7,10,8”,然后两边分别处理,进行快排(当你看到这里可能会有很多疑问???这怎么搞啊,这得多复杂啊)。其实我们在编写程序时是将以上的原理编写为一个函数,这样做方便我们在进行第一次探测后,利用函数递归对左右两边的子序列再次进行操作。。。。emm先给大家剧透点代码
quicksort(left, i-1);//左边进行快排
quicksort(i+1, right);//右边进行快排
这是在函数quicksort中再次调用函数(看不懂是肯定的,有印象就行)。。。。接着往下看。。。
回归第一次探测后,左边的子序列为“3,1,2,4,5”,然后再回想一下快排的原理,把第一个数作为基准数,哨兵们准备出发了(当然还是序列右边的“哨兵j”先出发哦),然后当两个哨兵都满足停下来的条件后,交换对应的数值。。然后相遇。。然后交换基准数3与相遇时对应的数值。。然后再次以3为分界点。。。。建议大家自己在纸上模拟一下(不然仍然会看的一脸懵逼,,,然后还建议大家多看几次,,,,我也是过来人,,,很理解大家的痛楚)。
废话少说,我们需要无线拆分序列,直到不可拆分出新的子序列为止(当然,这些都是通过函数递归来实现的)。。
到此,排序完全结束。。。总结一下,快排的每一轮处理其实就是将这一轮的基准数归位,归为后的数不需要再次进行排序,直到所有的数归位,排序over。来个霸气的图!!!
以上就是十分详细的处理过程了,希望大家可以耐心的看完哦。
代码实现:
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com