算法之分治——最坏情况线性时间的选择

思路:在基础版本的选择算法上,保证每一次都是平衡的划分

#include<iostream>
using namespace std;
int a[1000];
int part(int b,int r,int x)//划分 
{
	swap(a[x],a[r]);
	int i=b-1;
	int j=b;
	while(j<=r)
	{
		if(a[j]<a[r])
		{
			swap(a[j],a[i+1]);
			i++;
		}
		j++;
	}
	swap(a[i+1],a[r]);
	return i+1;
}
void sort(int b,int r)//选择排序 
{
	for(int i=b;i<r;i++)
	{
		for(int j=i+1;j<=r;j++)
		{
			if(a[i]>a[j]) swap(a[i],a[j]);
		}
	} 
}
int select(int b,int r,int k)//选择算法 
{
	if(r-b<5)//临界条件,当小于5个数时,直接排序即可 
	{
		sort(b,r);
		return a[b+k-1];
	}
	int g=(r-b+1)/5;
	int j=1;
	int t=b;
	int p=b;
	while(j<=g)//每5个分成一组。找出每组的中位数 
	{
		sort(t,t+4);
		swap(a[p],a[t+2]);//把中位数都放到前面的第p个位置,以便进行排序找出中值的中值
		t=t+5;
		p++;			 
		j++;
	}
	int y=(r-b+1)%5;
	if(y!=0) 
	{
		sort(t,t-1+y);
		swap(a[p],a[t+y/2]);
		g++;
	}
	sort(b,b+g-1);
	int x=(g+b-1+b)/2;//中值的中值的下标 
	int pos=part(b,r,x);//进行划分
	int m=pos-b+1; //用个数来比较更简洁 
	if(k<m) return select(b,pos-1,k);//递归 
	if(k==m) return a[pos];
	if(k>m) return select(pos+1,r,k-m);	
} 
int main()
{
	int n,k;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	cin>>k;
	cout<<select(1,n,k);//寻找第K位   	 
}
点赞