多种方法 http://blog.csdn.net/v_july_v/article/details/6370650
在增加一种:败者树http://blog.csdn.net/fisher_jiang/article/details/2473698
下面是自己实现的两种:
// 编程之美-寻找最大的K个数.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
#define N 3900
#define K 39
double Arr[N];// 可以利用原来数组中的第1个到 第K个 作为堆 但是会改变原来的数组
/*
double heap[K+1];//堆数组 K个元素的堆(o(N*log(K))) 比 建立 N个元素的堆o(N+K*log(N))的时间复杂度高,但是用 K个 空间复杂度较好
void HeapJust(double *arr, int r,int m)//小跟堆
{
for(int j=2*r;j<=m;j*=2)
{
if(j+1<=m&&arr[j]>arr[j+1])j++;
if(arr[r]<arr[j])break;
double temp=arr[j];
arr[j]=arr[r];
arr[r]=temp;
r=j;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
for(int i=0;i<N;i++)
Arr[i]=rand()%100000;
for(int i=0;i<K;i++)
heap[i+1]=Arr[i];
for(int i=K/2;i>=1;i--)// construct the heap canbe o(n)
HeapJust(heap,i,K);
for(int i=K;i<N;i++)//遍历数组 中剩余的所有元素,找出最大的K个
{
if(Arr[i]>heap[1])
{
heap[1]=Arr[i];//堆中最小的元素被替代
HeapJust(heap,1,K);
}
}
for(int i=1;i<=K;i++)
cout<<heap[i]<<" ";
cout<<endl;
for(int i=0;i<N;i++)
if(Arr[i]>32756)cout<<Arr[i]<<" ";
//cout<<"result is "<<Arr[0]<<endl;
system("pause");
return 0;
}*/
//http://blog.csdn.net/v_JULY_v/article/details/6403777
//快速排序 采用 中位数的中位数 即是在最坏的情况下 可达到 线性时间复杂度(常数比较大) 一定是要改变原来的数组了,否则开辟 N 大空间
//5个数而言 6次比较 可找中间元,7次比较可 排序
// 进过测试 堆排序方法效率远比 快速选择方法 高 当N为五位数时,选择排序执行困难,虽然算法本身的时间复杂度为O(n),
// 但算法其他的额外开销占用大量时间,而且采用递归,递归每次又要开辟一定的空间 来存储临时的中位数。会改善吗?待续。。。
void Swap(double *p,double *q)
{
double temp = *p;
*p=*q;
*q=temp;
}
double middle5(double *Arr, int i)//以i为起始点的5个元素
{
if(Arr[i]>Arr[i+1]) Swap(&Arr[i],&Arr[i+1]);
if(Arr[i+2]>Arr[i+3]) Swap(&Arr[i+2],&Arr[i+3]);
if(Arr[i+1]>Arr[i+3])
{
Swap(&Arr[i+1],&Arr[i+3]);
Swap(&Arr[i],&Arr[i+2]);
}// Arr[i] Arr[i+3] canbe excluded
if(Arr[i+2]>Arr[i+4])Swap(&Arr[i+2],&Arr[i+4]);
if(Arr[i+1]>Arr[i+4])
{
Swap(&Arr[i+1],&Arr[i+4]);//Arr[i+4]canbe excluded
Swap(&Arr[i],&Arr[i+2]);
}
if(Arr[i+1]>Arr[i+2]) return Arr[i+1];
else return Arr[i+2];
}
double middle4(double *Arr, int i)//以i为起始点的4个元素 返回第二大的
{
if(Arr[i]>Arr[i+1]) Swap(&Arr[i],&Arr[i+1]);
if(Arr[i+2]>Arr[i+3]) Swap(&Arr[i+2],&Arr[i+3]);
if(Arr[i+2]>Arr[i+1])
return Arr[i+1];
else
{
if(Arr[i+2]>Arr[i]) return Arr[i+2];
else return Arr[i];
}
}
double middle3(double *Arr, int i)//以i为起始点的3个元素
{
if(Arr[i]>Arr[i+1]) Swap(&Arr[i],&Arr[i+1]);
if(Arr[i+2]>Arr[i+1])
return Arr[i+1];
else
{
if(Arr[i+2]>Arr[i]) return Arr[i+2];
else return Arr[i];
}
}
double middle2(double *Arr, int i)//以i为起始点的2个元素
{
if(Arr[i]>Arr[i+1]) Swap(&Arr[i],&Arr[i+1]);
return Arr[i];
}
double middle1(double *Arr, int i)//以i为起始点的1个元素
{
return Arr[i];
}
double selectpivot(double *Arr,int i,int n)// 寻找起始点为i 长度为n的一段的中位数
{
int m=n/5,r=n%5,j,k;
if(r!=0)
{
double *pivot=new double[m+1];//存储n个元素的中位数
for(j=i,k=0;k<m&&j<i+n;j+=5,k++)
{
pivot[k]=middle5(Arr,j);
}
if(r==4)
pivot[m]=middle4(Arr,5*m+i);
else if(r==3)
pivot[m]=middle3(Arr,5*m+i);
else if(r==2)
pivot[m]=middle2(Arr,5*m+i);
else if(r==1)
pivot[m]=middle1(Arr,5*m+i);
if(m+1>5) return selectpivot(pivot,0,m+1);
else if(m+1==5) return middle5(pivot,0);
else if(m+1==4) return middle4(pivot,0);
else if(m+1==3) return middle3(pivot,0);
else if(m+1==2) return middle2(pivot,0);
else if(m+1==1) return middle1(pivot,0);
}
else
{
double *pivot=new double[m];//存储n个元素的中位数
for(int j=i,k=0;k<m&&j<i+n;j+=5,k++)
{
pivot[k]=middle5(Arr,j);
}
if(m>5) return selectpivot(pivot,0,m);
else if(m==5) return middle5(pivot,0);
else if(m==4) return middle4(pivot,0);
else if(m==3) return middle3(pivot,0);
else if(m==2) return middle2(pivot,0);
else if(m==1) return middle1(pivot,0);
}
}
double quickSelect(double *Arr, int i, int n,int k)//form i on n is the number k 表示 第几小的
{
double pivot = selectpivot(Arr,i,n);
//对于所有的数各不相同的情况,要找到pivot的位置,才能保证左面的都比其小,右面的都大,若有相同的数,则可以让左面的不比其大,右边的不比其小,可以不用找pivot的位置
int pos=0;
for(int j=i;j<i+n;j++)
if(Arr[j]==pivot)
{ pos=j; break;}
int low=i,high=i+n-1;
Arr[pos]=Arr[high];
//double temp=Arr[high];
while(low<high)
{
//?while(low<high&&Arr[low]<pivot)low++;
while(low<high&&Arr[low]>pivot)low++;
Arr[high]=Arr[low];
//?while(low<high&&Arr[high]>pivot)high--;
while(low<high&&Arr[high]<pivot)high--;
Arr[low]=Arr[high];
}
Arr[low]=pivot;
if(k==low-i+1) return Arr[low];
else if(k>low-i+1) return quickSelect(Arr,low+1,i+n-1-low,k-(low-i+1));
else return quickSelect(Arr,i,low-i,k);
}
int _tmain(int argc, _TCHAR* argv[])
{
for(int i=0;i<N;i++)
Arr[i]=rand()%100000;
//for(int i=0;i<N;i++)
//cout<<Arr[i]<<" ";
//cout<<endl;
cout<<"result is "<<quickSelect(Arr,0,N,K)<<endl;
//for(int i=0;i<N;i++)
// cout<<Arr[i]<<" ";
system("pause");
return 0;
}