利用快速排序的思想,选择第k大(或小)的数。
具体地,利用快速排序的划分思想,每次将数组划分为两部分,确定该第k大(或小)的元素在哪一个部分,然后对该部分递归进行划分,直到找到第k大(或小)的元素。快速排序期望时间复杂度为O(n log n),快速选择算法期望时间复杂度为O(n)。
关于枢纽元的选择:
- 选取第一个或最后一个元素,一般做法。
- 三数取中值法。取首、中、尾3个位置的元素的中间值,并将该中间值交换至第一个或最后一个元素,继续同1进行排序。
- 中位数的中位数法。
- 将所有元素进行组分,如每5个为一组,可分为[n/5]组。
- 对每个组进行排序,并得到该组的中位数。
- 递归调用步骤 a, b 直到获得最终的中位数。
快速选择算法的一个实现:(三值取中值法)
1 package com.yan.algorithmTest; 2 3 /** 4 * quick select algorithm which is very similar to quick sort algorithm. 5 * it suffers the average complication of O(n), while quick sort algorithm suffers O(n log n). 6 * @author Yan 7 * 8 */ 9 public class QuickSelectTest { 10 private static int[] data = new int[] { 5, 3, 4, 6, 2, 1, 7, 8, 10, 9 }; 11 private static int k = 4; 12 13 public QuickSelectTest() { 14 } 15 16 public static void main(String[] args) { 17 int result = quickSelect(data, k, 0, data.length - 1); 18 System.out.println(result); 19 } 20 21 public static int quickSelect(int[] data, int k, int start, int end) { 22 if (k > data.length || start > end) { 23 return -1; 24 } 25 /* 26 * 与quick sort 相同的partition算法(分割算法)。 27 */ 28 int pivot = end; 29 int left = start; 30 int right = end; 31 while (left < right) { 32 while (data[left] <= data[pivot] && left < right) { 33 left++; 34 } 35 while (data[right] >= data[pivot] && left < right) { 36 right--; 37 } 38 swap(data, left, right); 39 } 40 swap(data, left, pivot); 41 /* 42 * 与快速排序相同,只是在recurse时,多了两个判断,即k的判断。因此,只有一个递归调用会执行。 相较于快速排序的期望时间复杂度O(n 43 * log n),快速选择的期望时间复杂度为O(n)。 44 */ 45 if (k - 1 > left) { 46 quickSelect(data, k, left + 1, end); 47 } 48 if (k - 1 < left) { 49 quickSelect(data, k, start, left - 1); 50 } 51 52 return data[k - 1]; 53 } 54 55 /* 56 * median-of-three,三值取中值法,获取首、中、尾三者中得中间值,并与枢纽元pivot,即尾(或首)交换。 57 */ 58 public static void medianPivot(int[] data, int start, int end) { 59 int center = (start + end) >> 1; 60 if (data[start] > data[center]) { 61 swap(data, start, center); 62 } 63 if (data[center] > data[end]) { 64 swap(data, end, center); 65 } 66 if (data[start] > data[end]) { 67 swap(data, end, start); 68 } 69 swap(data, end, center); 70 } 71 72 public static void swap(int[] data, int x, int y) { 73 int temp = data[x]; 74 data[x] = data[y]; 75 data[y] = temp; 76 } 77 }