直接切入主题,快速排序分为两过程 :挖抗填数 + 分治法
先说下分治法,顾名思义就是“分而治之”的核心思想。简单举个例子体会一下:现在有100个人需要按照身高排成一列。首先,定个身高基准1.7m(定得太高和太低都会打破平衡),高与1.7m的都站在一列的右端,低于1.7m的都站在一列的左端。1.7m即为左右端的分割基准。这样左右两端就可以同时按照身高进行排序了,排完之后合并起来不是很简单了。这样做,效率是不是大大提高了。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
5 | 4 | 6 | 3 | 1 | 7 | 2 | 8 |
定义一个数组a,初始时,i = 0,j = 7 ,基准值X =a [0] = 5 (也可以设置为中间一个数,或者最后一个数)
可以假设基准值X为一个坑,需要用一个数往里面填,现在从j开始向前找一个<=X的数。当j=6时,将a[6]挖出填入到a[0]中,即a[0]=a[6],i ++ ; 接下来a[6]成了新的坑,我们从i开始向后找一个>X的数,当i=2时,将a[2]挖出填入到a[6]中,即a[6] = a[2],j --。
数组变为
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
2 | 4 | 5 | 3 | 1 | 7 | 6 | 8 |
此时,i = 2 为一个坑,j=5,X=5。继续上面的步骤,从j = 5向前找一个<=X的数,当j=4时,将a[4] 挖出填入a[2],即a[2] = a[4], i++,a[4]成了新坑,我们从i =3开始向后找一个>X的数,当i = 4 = j 时。退出!由于a[4] 是上次挖的坑,因此需要把X给它填上。
此时数组变为
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
2 | 4 | 1 | 3 | 5 | 7 | 6 | 8 |
观察后,可以发现跟身高排队一样吧,基准值5的左边全是小于5的 ,而右边全是大于5的。只要将a[0-3]和a[5-7]这两个子数组重复上述步骤即可完成快速排序。
挖坑填数总结:
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
思路清晰了,代码就好写了
package algorithm;
public class QuickSort {
public static void quickSort(int arr[], int left, int right) {
if (left < right) {
int i = left, j = right, x = arr[left]; // X 为基准值,这里默认为第一个数
while (i < j) {
while (i < j && arr[j] >= x) { // 从右向左找第一个小于X的数
j--; // 找不到就-1继续找
}
if (i < j) {
arr[i++] = arr[j];
// arry[i] = arry[j];
// i++;
}
while (i < j && arr[i] < x) { // 从左向右找第一个大于X的数
i++; // 找不到就+1继续找
}
if (i < j) {
arr[j--] = arr[i];
// arry[j] = arry[i];
// j--;
}
}
// 当i == j 时结束。 把基准值填入最后坑中
arr[i] = x;
// 这里采用分治法 继续让两个子数组继续排序
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
}
public static void main(String[] args) {
int[] reourse = {53,44,64,32,13,74,22,84};
quickSort(reourse, 0, reourse.length -1);
for (int i : reourse) {
System.out.print(i + "\t");
}
}
}