快速选择算法

利用快速排序的思想,选择第k大(或小)的数。

具体地,利用快速排序的划分思想,每次将数组划分为两部分,确定该第k大(或小)的元素在哪一个部分,然后对该部分递归进行划分,直到找到第k大(或小)的元素。快速排序期望时间复杂度为O(n log n),快速选择算法期望时间复杂度为O(n)

 

关于枢纽元的选择:

  1. 选取第一个或最后一个元素,一般做法。
  2. 三数取中值法。取首、中、尾3个位置的元素的中间值,并将该中间值交换至第一个或最后一个元素,继续同1进行排序。
  3. 中位数的中位数法。
    1. 将所有元素进行组分,如每5个为一组,可分为[n/5]组。
    2. 对每个组进行排序,并得到该组的中位数。
    3. 递归调用步骤 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 }

 

posted on 2016-06-01 21:51  Yanspecial  阅读(1399)  评论(0编辑  收藏  举报