《算法導論》第九章----中位數和順序統計學

《算法導論》學習記錄目錄html

本章主要講了如何在一個集合裏找出第i個順序統計量(即第i個小的元素),能夠定義選擇問題(n個元素中的第i個小的元素,即在n個元素裏找出一個元素,這個元素大於其餘i-1個元素)。算法

若是咱們用堆排序或合併排序(Ο(nlgn))對該集合進行排序,而後直接找出第i個元素便可。這樣一來,選擇問題運行時間爲Ο(nlgn)。可是本章講其餘兩種方法可使的選擇問題的運行時間爲O(n),分別爲以指望線性時間作選擇和最壞狀況線性時間的選擇。(PS:本人能力不足,對於最壞狀況線性時間的選擇的算法還在看,不能將其實現。。。。因此下文不會出現。。。)數組

 

最小值最大值dom

最小值和最大值均可以經過n-1次比較找出,先假設最小值(最大值)爲第一個元素,再與剩下的元素比較,在比較過程當中找出最小值(最大值)。ide

 1 int minimum(int A[], int length){
 2     int min = A[0];
 3     int i;
 4     for(i = 1; i < length; i++){
 5         if(min > A[i])
 6             min = A[i];
 7     }
 8 
 9     return min;
10 }
minimun

同時找出最小值最大值性能

若是獨立找出最小值和最大值總共用了2n-2次比較。可是能夠用3*floor(n / 2)次比較就能夠同時找出最小值和最大值。方法爲成對進行比較,先一對元素互相比較,而後較小的元素與最小值比較,較大的元素與最大值比較,這樣每兩個元素只須要比較3次。對於最小值和最大值初值,咱們將元素數目分爲奇偶數兩種處理:若是爲奇數,最小值和最大值的初值都爲第一個元素的值,而後成對處理;若是爲偶數,第一對元素先比較,較小的爲最小值的初值,較大的爲最大值的初值。學習

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int main(){
 5     int number, i;
 6     int min, max;
 7     int t_max, t_min;
 8     scanf("%d", &number);
 9     int *array = malloc(number * sizeof(int));
10     
11     for(i = 0; i < number; i++)
12         scanf("%d", &array[i]);
13 
14     if(number % 2){                 //奇數
15         min = max = array[0];
16         i = 1;
17     }
18     else{                           //偶數
19         if(array[0] > array[1]){
20             max = array[0];
21             min = array[1];
22         }
23         else{
24             max = array[1];
25             min = array[0];
26         }
27         i = 2;
28     }
29 
30     for(; i < number; i += 2){
31         if(array[i] > array[i+1]){  //每對元素先進行比較
32             t_max = array[i];
33             t_min = array[i+1];
34         }
35         else{
36             t_max = array[i+1];
37             t_min = array[i];
38         }
39         
40         if(t_max > max)             //較大的元素與最大值比較
41             max = t_max;
42         if(t_min < min)             //較小的元素與最大值比較
43             min = t_min;
44     }
45 
46     printf("Min is %d, Max is %d.\n", min, max);
47     return 0;
48 }
minmax

 

以指望線性時間作選擇spa

不少人會以爲在n個元素裏面找出第i個小的值會比找出最小值要困難,可是以指望線性時間作選擇的算法的漸進運行時間爲Θ(n)。本章介紹的該算法是分治算法,以快速排序算法爲基礎,對數組進行遞歸劃分。可是該算法不須要對劃分的兩邊進行處理,而只須要處理劃分的一邊,這樣一來該算法的指望運行時間爲Θ(n)。code

該算法爲隨機算法,使用了快速排序中的隨機化版本(連接在此)的randomized_partition方法(PS:調用方法的註釋見前連接)。htm

代碼中還有迭代版本(練習9.2-3)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int randomized_partition(int A[], int p, int r);
 5 
 6 int partition(int A[], int p, int r);
 7 
 8 int randomized_select(int A[], int p, int r, int i);
 9 
10 int randomized_select_iteration(int A[], int p, int r, int i);
11 
12 int main(){
13     int number;
14     scanf("%d", &number);
15     int *array = malloc(number * sizeof(int));
16 
17     int i;
18     for(i = 0; i < number; i++)
19         scanf("%d", &array[i]);
20 
21     int which;
22     scanf("%d", &which);
23 
24     //int select = randomized_select(array, 0, number-1, which);
25     int select = randomized_select_iteration(array, 0, number-1, which);
26     printf("%d\n", select);
27     return 0;
28 }
29 
30 int randomized_partition(int A[], int p, int r){
31     int i = p + rand() % (r - p + 1);
32     int temp = A[i];
33     A[i] = A[r];
34     A[r] = temp;
35     return partition(A, p, r);
36 }
37 
38 int partition(int A[], int p, int r){
39     int x = A[r];
40     int i = p - 1;
41     int j;
42     for(j = p; j <= r -1; j++){
43         if(A[j] <= x){
44             i++;
45             int temp = A[i];
46             A[i] = A[j];
47             A[j] = temp;
48         }
49     }
50     int temp = A[i+1];
51     A[i+1] = A[r];
52     A[r] = temp;
53 
54     return i+1;
55 }
56 
57 /*
58  * 在數組下標爲p到r中找出第i小的元素
59  */
60 int randomized_select(int A[], int p, int r, int i){
61     if(p == r)
62         return A[p];
63     int q = randomized_partition(A, p, r);       //在下標爲p到r中隨機找一個元素,以該元素爲主元素劃分數組,並返回該元素的位置
64     int k = q - p + 1;                          //主元素在數組下標爲p到r中裏爲第幾小的元素
65     
66     if(i == k)                                 //若是i等於k,主元素爲要找的值
67         return A[q];
68     else if(i < k)                              //若是i小於k,說明要找的第i小的元素比主元素要小,因此只出如今主元素的左邊的子數組裏,而這時,第i小的元素在左邊子數組依然爲第i小。
69         return randomized_select(A, p, q-1, i);
70     else                                            //若是i大於,說明要找的第i小元素比主元素要大,因此只出如今主元素的右邊的子數組裏,而這時,第i小的元素在右邊子數組應該爲i-k小。子數組的位置爲q+1,而q位置的元素爲第k小的元素。
71         return randomized_select(A, q+1, r, i-k);
72 }
73 
74 
75 /*
76  * 下面爲迭代實現
77  */
78 int randomized_select_iteration(int A[], int p, int r, int i){
79     if(p == r)
80         return A[p];
81 
82     while(1){
83         int q = randomized_partition(A, p, r);
84         int k = q - p + 1;
85 
86         if(i == k)
87             return A[q];
88         else if(i < k){
89             r = q - 1;
90         }
91         else{
92             p = q + 1;
93             i = i - k;
94         }
95     }
96 }
randomized_select

這個算法看起來會遞歸調用含有0個元素的子數組,可是這種狀況不會發生。(長度爲0的數組,會直接返回,不會遞歸調用)

這個算法的最壞狀況運行時間爲Θ(n2),即每次劃分都是按餘下的元素中最大的進行劃分。可是該算法的平均狀況性能較好,並且是隨機化,故沒有哪種特殊的輸入會致使最壞狀況的發生。

具體關於指望的計算請見算導原文。。。。(有不少的計算和證實還在看。。。。)

雖然本章的頁數不多,可是有不少習題和思考題。。。。之後必定要好好作了,並把最壞狀況線性時間的選擇也補上。。。。

繼續努力!!!

相關文章
相關標籤/搜索