快速排序是冒泡排序的改进版,也是最好的一种内排序,在很多面试题中都会出现,也是作为程序员必须掌握的一种排序方法。
基本思想
快速排序使用分治法策略来把一个序列分为两个子序列,基本步骤为:
- 先从序列中取出一个数作为基准数;
- 分区过程:将把这个数大的数全部放到它的右边,小于或者等于它的数全放到它的左边;
- 递归地对左右子序列进行步骤2,直到各区间只有一个数。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
下面我们用图解来说明一下这个排序算法
以一个数组作为示例,取区间第一个数为基准数。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
72 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
初始时,i = 0; j = 9; temp = a[i] = 72
由于已经将 a[0] 中的数保存到 temp 中,可以理解成在数组 a[0] 上挖了个坑,可以将其它数据填充到这来。
从 j 开始向前找一个比 temp 小或等于 temp 的数。当 j = 8,符合条件,将 a[8] 挖出再填到上一个坑 a[0] 中。
a[0] = a[8]; i++; 这样一个坑 a[0] 就被搞定了,但又形成了一个新坑 a[8],这怎么办了?简单,再找数字来填 a[8] 这个坑。这次从i开始向后找一个大于 temp 的数,当 i = 3,符合条件,将 a[3] 挖出再填到上一个坑中 a[8] = a[3]; j–;
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 88 | 85 |
i = 3; j = 7; temp = 72
再重复上面的步骤,先从后向前找,再从前向后找。
从 j 开始向前找,当 j = 5,符合条件,将 a[5] 挖出填到上一个坑中,a[3] = a[5]; i++;
从i开始向后找,当 i = 5 时,由于 i==j 退出。
此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将 temp 填入 a[5]。
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 42 | 60 | 72 | 83 | 73 | 88 | 85 |
可以看出 a[5] 前面的数字都小于它,a[5] 后面的数字都大于它。因此再对 a[0…4] 和 a[6…9] 这二个子区间重复上述步骤就可以了。
对挖坑填数进行总结
1.i = L; j = R; 将基准数挖出形成第一个坑 a[i]。
2.j-- 由后向前找比它小的数,找到后挖出此数填前一个坑 a[i] 中。
3.i++ 由前向后找比它大的数,找到后也挖出此数填到前一个坑 a[j] 中。
4.再重复执行 2,3 二步,直到 i==j,将基准数填入 a[i] 中。
package quickSort;
public class QuickSort {
private static int count;
/**
* 测试
* @param args
*/
public static void main(String[] args) {
int[] num = {3,45,78,64,52,11,64,55,99,11,18};
System.out.println(arrayToString(num,"未排序"));
QuickSort(num,0,num.length-1);
System.out.println(arrayToString(num,"排序"));
System.out.println("数组个数:"+num.length);
System.out.println("循环次数:"+count);
}
/**
* 快速排序
* @param num 排序的数组
* @param left 数组的前针
* @param right 数组后针
*/
private static void QuickSort(int[] num, int left, int right) {
//如果left等于right,即数组只有一个元素,直接返回
if(left>=right) {
return;
}
//设置最左边的元素为基准值
int key=num[left];
//数组中比key小的放在左边,比key大的放在右边,key值下标为i
int i=left;
int j=right;
while(i<j){
//j向左移,直到遇到比key小的值
while(num[j]>=key && i<j){
j--;
}
//i向右移,直到遇到比key大的值
while(num[i]<=key && i<j){
i++;
}
//i和j指向的元素交换
if(i<j){
int temp=num[i];
num[i]=num[j];
num[j]=temp;
}
}
num[left]=num[i];//将标记位和最后一个比他小的数换位置
num[i]=key;//key在他正确的位置上
count++;
QuickSort(num,left,i-1);
QuickSort(num,i+1,right);
}
/**
* 将一个int类型数组转化为字符串
* @param arr
* @param flag
* @return
*/
private static String arrayToString(int[] arr,String flag) {
String str = "数组为("+flag+"):";
for(int a : arr) {
str += a + "\t";
}
return str;
}
}
代码转自下文博客,并含有例子分析
原文:https://blog.csdn.net/qq_36186690/article/details/82470451