快速排序也是使用分治策略,用partition函数将序列一分为二(O(n))后,将子序列递归排序((1 / n) * ∑[T(k) + T(n - k - 1)]),最后合并有序子序列(O(1)),T(n) = O(n) + (1 / n) * ∑[T(k) + T(n - k - 1)] = O(n * logn)。
一、快速排序
1、快速排序的实现
public static void quickSortCore(int[] arr, int lo, int hi) { if (lo < hi) { int mid = partition(arr, lo, hi); quickSortCore(arr, lo, mid - 1); quickSortCore(arr, mid + 1, hi); } }
2、partition的实现
public static int partition(int[] arr, int lo, int hi) { // 令arr[hi]为pivot // 将原数组分为小于pivot、pivot和大于等于pivot三部分 swap(arr, lo + (int) Math.random() * (hi - lo + 1), hi); int small = lo - 1; while (lo < hi) { if (arr[lo] < arr[hi]) { swap(arr, ++small, lo++); } else { lo++; } } swap(arr, ++small, hi); return small; }
3、源码
二、剑指offer[40]
最小的k个数 题解
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4
快排的partition函数会将原序列分为左右两个子序列,左边序列都小于pivot,右边序列都大于或等于pivot,当pivot为数组的第k个元素时,数组中pivot及其之前的元素都小于右边序列,即为n个整数中最小的k个数。
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { if (input == null || input.length == 0 || input.length < k || k == 0) { return new ArrayList<>(); } // 在数组中寻找位置为k - 1的pivot int start = 0, end = input.length - 1; int index = partition(input, start, end); while (index != k - 1) { if (index < k - 1) { start = index + 1; } else { end = index - 1; } index = partition(input, start, end); } // 收集这k个数 ArrayList<Integer> res = new ArrayList<>(); for (int i = 0; i <= index; i++) { res.add(input[i]); } return res; }
上述解法并不是本题的最优解,但可作为快速排序partition的应用。最优解见题解。