分治法|輸出前k大的數

分治法|輸出前k大的數(北大MOOC程序設計與算法二 第五週測驗)

給定一個數組,統計前k大的數並且把這k個數從大到小輸出。

輸入

第一行包含一個整數n,表示數組的大小。n < 100000。
第二行包含n個整數,表示數組的元素,整數之間以一個空格分開。每個整數的絕對值不超過100000000。
第三行包含一個整數k。k < n。

輸出

從大到小輸出前k大的數,每個數一行。

輸入樣例

10
4 5 6 9 8 7 1 2 3 0
5

輸出樣例

9
8
7
6
5

解題思想

  1. 排序後輸出,複雜度O( nlogn )。
    分治處理,複雜度O( n+mlogm )。
  2. 把前m大的數都移到數組最右邊,對這m個數排序
  3. 如何將前m大的數移到最右邊。設 key=a[0], 像快速排序那樣將 key 移到適當位置,使得比 key 小的元素都在它左邊,比 key 大的都在它右邊。比較 key 此時所在位置即 a[i] 起至數組末尾的元素個數是否滿足m個:小於m,在key左邊再移動適當的數到最右邊;大於m,則往key的右邊再縮小。

代碼

#include<iostream>
#include<algorithm>	//偷懶用了sort函數
using namespace std;
const int N=100005;
int a[N];
int n,k;	//n是數組元素個數,k是前k個最大的數

void swap(int &a,int &b){
	int t;
	t=a;	a=b;	b=t;
	return;
}
void array(int a[],int s,int e,int k);

int main()
{
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	cin>>k;
	array(a,0,n-1,k);
	sort(a+n-k,a+n);
	for(int i=0;i<k;i++){
		cout<<a[n-1-i]<<endl;
	}
	return 0; 
}

void array(int a[],int s,int e,int k){
	if(s>=e)
		return;
	int key=a[s];
	int i=s,j=e;
	while(i!=j){
		while(j>i&&a[j]>=key){
			--j;
		}
		swap(a[i],a[j]);
		while(i<j&&a[i]<=key){
			++i;
		}
		swap(a[i],a[j]);
	}
	if((e-i+1)<k
		array(a,s,i-1,k-e+i-1);
	else if((e-i+1)>k)
		array(a,i+1,e,k);
	else
		return;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章