第九章 中位元和順序統計學
9.1 最小值和最大值
在一個有n個元素的集合中,要做多少次比較才能確定其最小元素呢?可以很容易地給出n-1次比較這個上界:依次查看集合中的每個元素,並記錄比較過程中的最小元素。同樣道理,最大值也可以通過n-1次比較找出來。這個演算法比較簡單,我就沒有寫程式實現了。
在某些應用中,必須找出n個元素集合中的最大值和最小值。按照上面的思路,可以對目標數組進行兩次掃描,便可獨立得到最小值和最大值。但這是不是最優的演算法呢?事實上,至多3floor(n/2)次比較就足以同時找出最大值和最小值。做法是記錄比較過程中遇到的最小值和最大值。並不是將每一個輸入元素與當前的最大值和最小值分別進行比較,而是成對地處理元素。先將一對輸入元素互相比較,然後把較小值與當前最小值進行比較,最大值與當前最大值進行比較,這樣每兩個元素需要進行三次比較,而不是四次。
C++語言實現
1 #include <iostream> 2 3 using namespace std; 4 5 struct XY 6 { 7 int max; 8 int min; 9 };10 11 XY returnXY(int x, int y)12 {13 XY maxminXY;14 if(x > y)15 {16 maxminXY.max = x;17 maxminXY.min = y;18 }19 else20 {21 maxminXY.max = y;22 maxminXY.min = x;23 }24 return maxminXY;25 }26 27 XY maxmin(int* arr, int length)28 {29 XY extremum;30 XY temp;31 extremum = returnXY(arr[0], arr[1]);32 if(length % 2 == 0)33 {34 for(int i = 2; i < length; i += 2)35 {36 temp = returnXY(arr[i], arr[i + 1]);37 if(extremum.max < temp.max)38 extremum.max = temp.max;39 if(extremum.min > temp.min)40 extremum.min = temp.min;41 }42 }43 else44 {45 for(int i = 2; i < length - 1; i += 2)46 {47 temp = returnXY(arr[i], arr[i + 1]);48 if(extremum.max < temp.max)49 extremum.max = temp.max;50 if(extremum.min > temp.min)51 extremum.min = temp.min;52 }53 if(arr[length - 1] > extremum.max)54 extremum.max = arr[length - 1];55 else if(arr[length - 1] < extremum.min)56 extremum.min = arr[length - 1];57 }58 return extremum;59 }60 61 int main()62 {63 XY maxminXY;64 int a[] = {22, 34, 95, 87, 56, 980, 12, 48};65 maxminXY = maxmin(a, 8);66 cout << "Max = " << maxminXY.max << " " << "Min = " << maxminXY.min << endl;67 return 0;68 }
在程式中,我用了一個結構體XY用於同時儲存最大值和最小值。函數XY returnXY(int x, int y)是擷取每對元素的最大值和最小值的函數。函數XY maxmin(int* arr, int length)是實現同時返回長度為length的數組的最大值和最小值的程式。
習題:在最壞情況下,利用n+ceil(lgn)-2次比較,即可找到n個元素中的第2小元素。(提示:同時找出最小元素)
對數組arr[1…n] 中元素成對的做比較,每次比較後將較小的數拿出,形成的數組再繼續這樣處理,直到剩下最後的一個,就是數組中最小的那個。在這個過程中,一共進行了n-1 次比較,樹根即為最小的元素。而第二小的元素一定是在這個過程中與根節點進行過比較的元素,因為只有最小的元素可以擊敗次小的元素。這樣的數最多有(lgn)個,在這些數中找到最小的元素需要進行ceil(lgn)-1次比較。因此總共所需的比較次數為n+ceil(lgn)-2次。