夜深人靜寫演算法———線性時間選擇(分治,最壞情況處理)
阿新 • • 發佈:2018-12-18
一: 線性時間選擇中,最壞情況下時間複雜度為O(n^2) , 但如果線上性時間內找到一個劃分基準,使得按照這個基準所劃分的兩個子陣列的長度至少為原陣列的k倍( 0<k<1)。
二:
(1) 將n個輸入的元素分成 (n-4)/5組,每一組都是5個元素,可能最後一個不是,用任意的排序演算法將每組的5個元素排好,然後取出5個元素的中位數。
(2)遞迴呼叫Select函式(見程式)找出這(n-4)/5箇中位數數的中位數,然後將這個中位數作為劃分基準,作為快速排序中的參考值進行排序。
三:
中位數的中位數x作為劃分基準時,可以保證圖中左上角的部分比x小,圖中右下角的部分比x大。所以通過x作為劃分基準可以保證大約四分之一的資料比x小,四分之一的陣列比x大。不會產生最後情況,該複雜度約為O(N) .
如圖所示:.
四:
程式如下:
#include <iostream> #include <algorithm> #include <stdio.h> #include <time.h> #include <stdlib.h> #define LENGTH 10 using namespace std; template <class Type> void swap(Type *a,Type *b){ Type c; c = *a; *a = *b; *b = c; } template <class Type> int Partition(Type a[],int p,int r,Type x){ //快排過程中參考值的下標 int sl = p-1; int sr = r+1; while(true){ while(a[++sl] <= x && sl <= r); while(a[--sr] > x && sr >= 0); if(sl > sr)break; swap(a[sl],a[sr]); } swap(a[p],a[sr]); return sr; } template <class Type> Type Select(Type a[],int p,int r,int n){ if(r - p < 75){ //如果陣列大小小於75 ,就通過普通排序給出 sort(&a[p],&a[r] + 1); return a[p+n-1]; }else{ for(int i = 0;i <= (r-p-4)/5;i++){ //分為 (n-4)/5組 sort(&a[p + i*5],&a[p + i*5+4] +1); //對每一組的5個元素排序 swap(a[p+i*5+2],a[p+i]); //將中位數交換到a[p+i] } Type x = Select(a,p,p+(r-p-4)/5, (r-p-4)/10); //因為中位數交換到a[p+i],所以前(r-p-4)/5個元素都是中位數,對這(r-p-4)/5個元素遞迴,找到中位數的中位數 x int q = Partition(a,p,r,x); //中位數的中位數x 作為參考值,進行快排。 int s = q - p + 1; if(s == n )return x; else if(s < n) return Select(a,q+1,r,n - s); else return Select(a,p,q-1,n); } } int main(){ int n; srand(time(NULL));n= rand()%LENGTH + 1; int a[LENGTH] = { 2,1,3,4,7,5,6,9,8,0}; cout<<"第"<<n<<"小的數是:"; cout<<Select(a,0,LENGTH-1,n); }