一、什么是快速排序
快速排序(Quick Sort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可以分别对着两部分记录继续进行排序,以达到整个序列有序。
二、快速排序的具体步骤
以下数组为例
12 | 4 | 15 | 8 | 88 | 10 | 18 | 9 | 23 | 25 |
先确定基准值(一般用第一个数作为基准值)
12 | 4 | 15 | 11 | 88 | 10 | 18 | 9 | 23 | 25 |
然后我们要把基准值放到数组的中间的位置某个位置,这个位置前面的数 ≤ 12,后面的数 ≥ 12,然后我们需要用到两个哨兵(i,j)来帮我们找到这个位置
12 | 4 | 15 | 11 | 88 | 10 | 18 | 9 | 23 | 25 |
i | j |
哨兵 i 和哨兵 j 相向而行来找这个位置,我们让哨兵 j 先走(文末解释为什么要让 j 先走),当哨兵 j 找到一个小于基准值的数之后停下,然后让哨兵 i 出发,当哨兵 i 找到一个大于基准值的数之后停下
12 | 4 | 15 | 11 | 88 | 10 | 18 | 9 | 23 | 25 |
i | j |
然后交换他们的数据
12 | 4 | 9 | 11 | 88 | 10 | 18 | 15 | 23 | 25 |
i | j |
重复哨兵 i 和哨兵 j 的寻找的过程
12 | 4 | 9 | 11 | 88 | 10 | 18 | 15 | 23 | 25 |
i | j |
交换位置
12 | 4 | 9 | 11 | 10 | 88 | 18 | 15 | 23 | 25 |
i | j |
哨兵 j 继续前进和哨兵 i 相遇
12 | 4 | 9 | 11 | 10 | 88 | 18 | 15 | 23 | 25 |
i j |
这个位置就是我们要找的位置,接着交换基准值和这个位置上的值
10 | 4 | 9 | 11 | 12 | 88 | 18 | 15 | 23 | 25 |
i j |
在这个位置上,他前面的数都小于我们的基准值,后面的数都大于我们的基准值。这样我们就把数组分成了两个部分,然后对这两个部分分别进行之间的操作
10 | 4 | 9 | 11 | 12 | 88 | 18 | 15 | 23 | 25 |
i | j |
10 | 4 | 9 | 11 | 12 | 88 | 18 | 15 | 23 | 25 |
i j |
9 | 4 | 10 | 11 | 12 | |||||
i j |
9 | 4 | 10 | 11 | 12 |
这样前半部分就也排好了,然后再接着排剩下的数据,还是重复之前的操作
4 | 9 | 10 | 11 | 12 |
后半部分也是如此
4 | 9 | 10 | 11 | 12 | 15 | 18 | 23 | 25 | 88 |
这样我们就得到了排好的数组
三、快速排序的代码实现
public class KuaiSuPaiXu {
public static void main(String[] args) {
int[] a = {25, 4, 15, 8, 88, 10, 18, 9, 23, 12};
quickSort(a,0,a.length-1);
for (int i:a){
System.out.print(i+" ");
}
}
public static void quickSort(int[] a, int begin, int end) {
if (begin>=end){
return;
}
// 初始化变量
int i = begin, j = end, flag;
flag = a[begin];
while (i < j){
// j先向前走,遇到小于基准值的数停止
while (j>i&&a[j]>=flag){
j--;
}
// i再向后走,遇到大于基准值的数停止
while (j>i&&a[i]<=flag){
i++;
}
// j和i交换数据
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// 交换基准数
a[begin] = a[i];
a[i] = flag;
// 分治
quickSort(a, begin, i-1);
quickSort(a, i+1, end);
}
}
结果如下:
四、补充为什么要让 j 先走
i 和 j 谁先走是和基准值的选择有关的,如果我们以数组的第一个数作为基准值,却让 i 先走,当 i 和 j 相遇的时候那个位置上的数可能会大于我们的基准值,这样的话再来交换基准值,就不能让基准值左边的数都小于基准值,右边的数都大于基准值。但是让 j 先走,当 i 和 j 相遇的时候,那个位置上的数就一定不会大于基准数,因为在这里我们以数组的第一个数作为基准值所以我们让 j 先走。
如果一定要让 i 先走那就以数组的最后一个数作为基准值