快速排序
一:荷兰国旗问题
在引入快速排序之前呢,我们先看一个经典的荷兰国旗问题。
直观的“分三块”的问题。
需求:
给定一个待排序列arr[ ],给定一个数num,经过排序把arr[ ]划分成
小于num ; 等于num ; 大于num 三部分。要求额外空间复杂度O(1),时间复杂度O(N)。
分析如下:
在arr[ ]左边设置一个小于区,在右边设置一个大于区,不断向中间逼近,最终中间就是相等的数字。
操作过程如下:
具体代码实现:
// 荷兰国旗问题
public static int[] netherlandsFlag(int[] arr, int L, int R) {
if (L > R) {
return new int[] { -1, -1 };
}
if (L == R) {
return new int[] { L, R };
}
int less = L - 1;
int more = R;
int index = L;
while (index < more) {
if (arr[index] == arr[R]) {
index++;
} else if (arr[index] < arr[R]) {
swap(arr, index++, ++less);
} else {
swap(arr, index, --more);
}
}
swap(arr, more, R);
return new int[] { less + 1, more };
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
解决了荷兰国旗问题,自然的就可以引出快排了。快排就是基于这样的一种原理实现的。
二:快速排序(递归实现)
快速排序是交换排序思想的一种具体实现。
对荷兰国旗问题稍加改变与优化就可以实现快速排序。
已知数组arr[ ],在arr[ ]中随机的取出一个数arr[i],经过荷兰国旗排序后就可以划分成三部分。小于arr[i]; 等于arr[i]; 大于arr[i]。等于arr[i]的那部分不用再动,我们接下来再对小于arr[i]和大于arr[i]的这两部分采用递归的方式再依次的划分,直到划分结束。。。。。
具体代码实现:
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
process(arr, 0, arr.length - 1);
}
public static void process(int[] arr, int L, int R) {
if (L >= R) {
return;
}
swap(arr, L + (int) (Math.random() * (R - L + 1)), R);
int[] equalArea = netherlandsFlag(arr, L, R);
process(arr, L, equalArea[0] - 1);
process(arr, equalArea[1] + 1, R);
}