1. 程式人生 > >夜深人靜寫演算法———線性時間選擇(分治,最壞情況處理)

夜深人靜寫演算法———線性時間選擇(分治,最壞情況處理)

一:     線性時間選擇中,最壞情況下時間複雜度為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);

}