我是少侠露飞。学习塑造人生,技术改变世界。
快速排序号称最优雅的算法之一,在开发中可能用得不算多,但是在一些场景下还是很出色的。最关键的是,各大厂面试官都爱问啊,你说要不要好好掌握吧。 然后就是网上很多快排的代码和讲解,少侠发现很多人自己压根都没搞清楚,代码的边界不清,扔进去一执行就报数组越界异常;要么就是一些人模拟的快排过程都是错的,这让真心想学习的人难免心累。所以少侠决定写一篇记录之,讲解未必是最好的,但代码一定是正确的。
分解:快排的核心就是首先选定一个主元pivot,然后将原数组分解成两个子数组A和B,保证A中的结果小于等于pivot,B中的结果都大于等于pivot。 解决:然后针对两个子数组A和B再递归的调用,按照上步分解的逻辑进行。 合并:我们知道,归并排序最后是需要合并子数组的。但在这里,好消息是快排是原址排序,不需要合并。
原理不难理解,但是初学者对这个过程可能还是比较模糊。这里少侠就选择一个数组,按照快排的过程一步一步展示给大家。 这里我们选择初始化数组[6,2,3,9,5,8]。 首先选择主元,怎么选呢,可以选择某一索引位置的值,也可以选择多个索引,然后取中位数的值作为主元。这里我们固定选择第一个元素为主元。
第一次分解的时候pivot=6,分解的目标就是把所有大于等于6的元素移动右边,小于等于6的元素移到左边。然后左指针i从起始位置开始,右指针j从结尾开始,循环的边界就是i<j。初始位置如下图:
每次从右边的指针判定。当右指针的值大于pivot时,右指针左移一位,直到遇到小于等于pivot的值。如下图:
当右指针的值小于pivot时,将当前值赋值给指针i对应的位置,同时i向右移动一位,如下图:
当发生上步的情况(即右指针因小于pivot而发生值的覆盖时候),需要进入该逻辑:就是开始判断左指针的元素值,如果小于pivot,就向右移动一位,直到遇到大于等于pivot的元素。
此时i移动到元素值为9的位置,也就是大于pivot,此时需要将此位置的值赋值给j位置并使得指针j左移一位,即:
注意看,此时i=j,左右指针重合,已经不满足循环边界条件(i<j)了,退出循环。但是此时i位置的值才是pivot应该在的位置,所以执行赋值操作将pivot赋值给nums[i]=pivot;得到本次分解的最终结果:
最后再对主元pivot两侧的数组{5,2,3}和{9,8}递归的调用上述过程,得到最终排序结果。
本篇参考书籍《算法导论》。下期还会写篇关于堆排序的博客,敬请期待,也欢迎点赞、关注。咱们下期再见。