前言
快速排序采用“分治”思想,在一组待排序的数字中,选择一个元素为基准,经过处理,使小于基准元素的数字都在它的左边,大于基准元素的数字都在它的右边,再递归处理基准元素的左右两段数字,最终使得所有数字有序排列。
技巧
基准元素选择为中间的数字
详解
假设有一个数组为 2 5 4 3 1 7
基准元素选择为中间的数字 4
,然后定义两个扫描指针,分别从两端扫描,从左往右,找到比 4 大的数字时,左指针就停止(即到 5
的地方就停止),从右往左,找到比 4 小的数字时,右指针就停止(即到 1
时就停止)
两个指针位置上的数字(5 和 1)进行交换
之后,再继续走,左指针向右走,走到 4
的地方就停止,右指针向左走,走到 3
的地方就停止,再进行交换
至此,左指针和右指针相撞,第一轮完成
最后,需要进行递归处理,分别用两个递归处理左右两段(以右指针,即 j
为分界)
然后就能得到排序好的数组了
代码模板
void quick_sort(int q[], int l, int r) {
if (l >= r) return; // 看左边界是否大于等于有边界,如果大于等于右边界,表明只有 1 个数或没有数,这个时候就不用排序了,直接返回
// 确定分界的基准点 x,以 (l + r) / 2 为界
int x = q[(l + r) / 2], i = l - 1, j = r + 1; // 因为下面使用的是 do-while 循环,要先执行一次 i++、j--,因此 i、j 的定义需要向外拓展一个单位
while (i < j) { // 当左右指针不相撞时
do i++; while (q[i] < x); // 如果 q[i] 比基准元素小,那么就移动指针
do j--; while (q[j] > x); // 如果 q[j] 比基准元素大,那么就移动指针
// 当上面的两个 do-while 后,i 会停在比基准元素大的第一个元素上,j 会停在比基准元素小的第一个(从右往左数)元素上
if (i < j) swap(q[i], q[j]); // 此时,交换 q[i] 与 q[j](注意需要判断一下 i < j)
}
// 递归处理左右两段,分治思想
quick_sort(q, l, j); // 以 j 为界
quick_sort(q, j + 1, r);
}