夜深人静写算法———线性时间选择(分治,最坏情况处理)

一:
    线性时间选择中,最坏情况下时间复杂度为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);

}

猜你喜欢

转载自blog.csdn.net/curtern/article/details/83513163