首页 > 代码库 > 快速选择 - 快速排序算法在查找中的应用

快速选择 - 快速排序算法在查找中的应用

如果要我们找出一个数组中的最小(最大)的元素,那么第一反应肯定是使用最小(最大)堆。时间复杂度等同于建堆的复杂度,这里是O(N)。

如果要我们找出一个数组中的第k个最小的元素,那么我们依然可以使用最小堆,删除掉k次的最小值,就得到了结果。复杂度是O(N + klogN)。

如果要我们找出一个数组的中值,那么我们使用最小堆,复杂度是O(NlogN)。

 

但是,如果我们使用快速排序的思路来做快速选择呢?步骤是这样的:

(1)如果待排元素集合S的大小为1,k也为1,则返回。

(2)合理选取枢纽pivot。

(3)以pivot为参照,将集合分为S1和S2和pivot它自己。

(4)如果pivot的位置就是k,则返回。如果k小于pivot的位置,则递归处理S1。如果k大于pivot的位置,则递归处理S2。

我们分析上述快速选择的时间复杂度,与快速排序相比,快速选择只有步骤(4)与之有异。快速排序是递归S1和S2,而快速选择是递归其中之一,节省一次递归。最坏的复杂度的情况和快速排序相仿,是O(N^2)。最好的情况的复杂度是O(N)。平均的情况的复杂度,书上说是O(N),这点我暂时没去证明。

 

代码如下:

  1 #include <cstdio>  2 #include <cstdlib>  3   4 #define MINLENGTH 10  5   6 typedef int Item;  7 // inlineʹSwapÄÚÁªÕ¹¿ª¡£Ìá¸ß³ÌÐòЧÂÊ¡£   8 void inline  9 Swap(Item* a, Item* b) 10 { 11     if (a != b) { 12         *a ^= *b; 13         *b ^= *a; 14         *a ^= *b; 15     } 16 }     17 // ÔÚarrÖÐÈ¡×óÖÐÓÒÈý¸öλÖ㬱Ƚϡ£pivotÈ¡ÖмäÖµ£¬½«pivot·ÅÔÚright-1µÄλÖÃÉÏ¡£ 18 // leftµÄλÖÃСÓÚpivot£¬rightµÄλÖôóÓÚpivot¡£  19 Item 20 Median3(Item arr[], int left, int right) 21 { 22     int center = (left + right) / 2; 23      24     if (arr[left] > arr[center]) { 25         Swap(&arr[left], &arr[center]); 26     } 27     if (arr[left] > arr[right]) { 28         Swap(&arr[left], &arr[right]); 29     } 30     if (arr[center] > arr[right]) { 31         Swap(&arr[center], &arr[right]); 32     } 33      34     Swap(&arr[center], &arr[right-1]); 35     return arr[right-1]; 36 } 37  38 void 39 InsertSort(int arr[], int len) 40 { 41     for (int i = 1; i < len; i++) { 42         int tmp = arr[i]; 43         int j; 44         for (j = i; j >= 1 && arr[j-1] > tmp; j--) { 45             arr[j] = arr[j-1]; 46         } 47         arr[j] = tmp; 48     } 49 } 50 // ÕâÀïÑ¡ÓÃi£¬jÓöµ½µÈÓÚpivotµÄÇé¿öÏÂÍ£Ö¹£¨ÒòΪÈç¹û²»Í£Ö¹£¬ÄÇ»á´ïµ½O(N^2)¡££© 51 // ÁíÍ⣬³ÌÐò¿¼ÂÇ´ýÅÅÊý×Ö²»ÉÙÓÚ3¸öµÄÇé¿ö¡£ÉÙÓÚ3¸öµÄ»°£¬ÐèÒª¿¼ÂǶîÍâµÄÌØÊâÇé¿ö¡£  52 void  53 QSelect(Item arr[], int key, int left, int right)  54 { 55     if (right - left >= MINLENGTH) { 56         int pivot = Median3(arr, left, right); 57         int i = left; 58         int j = right - 1; 59         for ( ; ; ) { 60             while (arr[++i] < pivot) {} 61             while (arr[--j] > pivot) {} 62             if (i < j) { 63                 Swap(&arr[i], &arr[j]); 64             } else { 65                 break; 66             } 67         } 68         Swap(&arr[i], &arr[right-1]); // ½«pivot·ÅÔÚiµÄλÖÃÉÏ¡£  69          70         if (key == i) { 71             return; 72         }  73         if (key < i) { 74             QSelect(arr, key, left, i - 1); 75         } else if (key > i) { 76             QSelect(arr, key, i + 1, right); 77         } 78     }  79     else { 80         InsertSort(arr + left, right - left + 1); 81     } 82 } 83  84 void 85 QuickSelect(Item arr[], int key, int len) 86 { 87     QSelect(arr, key, 0, len-1); 88 } 89  90 int  91 main(int argc, char** argv) 92 { 93     Item arr[100000] = {0}; 94      95     for (int i = 0; i < 100000; i++) { 96         arr[i] = 100000/(i+1); 97     } 98  99     int key = 50000;100     QuickSelect(arr, key, 100000);101 102     printf("%d\n", arr[key]);103     104     105     system("pause");106     107     return 0;108 }

 

快速选择 - 快速排序算法在查找中的应用