快速排序算法(Quicksort),简称为“快排”,利用的是分治思想。
快排思想:(要排序数组中下标从 p 到 r 之间的一组数据)
选择 p 到 r 之间的任意一个数据作为 pivot(分区点)。 遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放到右边,将 pivot 放到中间。 经过这一步骤之后,数组 p 到 r 之间的数据就被分成了三个部分,前面 p 到 q-1 之间都是小于 pivot 的,中间是 pivot,后面的 q+1 到 r 之间是大于 pivot 的。
根据分治、递归的处理思想,可以用递归排序下标从 p 到 q-1 之间的数据和下标从 q+1 到 r 之间的数据,直到区间缩小为 1,所有的数据都有序了。
荷兰国旗问题 快速排序思想中数据按大小分区也即荷兰国旗问题:
给定一个数组arr和一个数num,要求对于[l,r]范围内的数,小于num的数放到最左边,等于num放到中间,大于num放到最右边。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static int [] netherlandsFlag(int [] arr, int l, int r) { int less = l - 1 ; int more = r; int index = l; while (index < more) { if (arr[index] < arr[r]) { swap(arr, index++, ++less); } else if (arr[index] > arr[r]) { swap(arr, index, --more); } else { index++; } } 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; }
普通快速排序 普通快速排序直接利用荷兰国旗问题递归求解,复杂度为O(N^2),当数组本身有序时,每次都需要对[0,r-1]做分区处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 ; } int [] equalArea = netherlandsFlag(arr, L, R); process(arr, L, equalArea[0 ] - 1 ); process(arr, equalArea[1 ] + 1 , R); }
随机快速排序* 随机快速排序是针对普通快排优化后的排序算法,也是通常快速排序所指的排序方式,复杂度为O(N*logN),最好最坏情况都是概率事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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); }
非递归实现快排 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public static class Op { public int l; public int r; public Op (int left, int right) { l = left; r = right; } } public static void quickSortByStack (int [] arr) { if (arr == null || arr.length < 2 ) { return ; } int N = arr.length; swap(arr, (int ) (Math.random() * N), N - 1 ); int [] equalArea = netherlandsFlag(arr, 0 , N - 1 ); int el = equalArea[0 ]; int er = equalArea[1 ]; Stack<Op> stack = new Stack<>(); stack.push(new Op(0 , el - 1 )); stack.push(new Op(er + 1 , N - 1 )); while (!stack.isEmpty()) { Op op = stack.pop(); if (op.l < op.r) { swap(arr, op.l + (int ) (Math.random() * (op.r - op.l + 1 )), op.r); equalArea = netherlandsFlag(arr, op.l, op.r); el = equalArea[0 ]; er = equalArea[1 ]; stack.push(new Op(op.l, el - 1 )); stack.push(new Op(er + 1 , op.r)); } } } public static void quickSortByQueue (int [] arr) { if (arr == null || arr.length < 2 ) { return ; } int N = arr.length; swap(arr, (int ) (Math.random() * N), N - 1 ); int [] equalArea = netherlandsFlag(arr, 0 , N - 1 ); int el = equalArea[0 ]; int er = equalArea[1 ]; Queue<Op> queue = new LinkedList<>(); queue.offer(new Op(0 , el - 1 )); queue.offer(new Op(er + 1 , N - 1 )); while (!queue.isEmpty()) { Op op = queue.poll(); if (op.l < op.r) { swap(arr, op.l + (int ) (Math.random() * (op.r - op.l + 1 )), op.r); equalArea = netherlandsFlag(arr, op.l, op.r); el = equalArea[0 ]; er = equalArea[1 ]; queue.offer(new Op(op.l, el - 1 )); queue.offer(new Op(er + 1 , op.r)); } } }