BFPTR算法求n个数中第k大(即第n-1-k小)的数,其思想是基于快速排序中对Partion的pivot值进行优化,快速排序中每一趟快排的pivot的选取一般是数组的首项或者尾项(数值比较随机),而BFPTR是每次选择5分中位数的中位数作为pivot进行下一趟快速排序的,这样做可以使算法的时间复杂度由最坏的O(n^2)变为O(n).
实现代码如下:
#include <iostream> using namespace std; const int maxn=1000; int a[maxn],n,k; //求有n个元素的数组a中第k大(第n-1-k小)的数 void Insert_Sort(int a[],int l,int r) {//由于只有5个数,插入排序即可 for(int i=l;i<=r;i++) { int tmp=a[i],j=i-1; for(;j>=l&&tmp<a[j];j--) a[j+1]=a[j]; a[j+1]=tmp; } } int Find_mid(int a[],int l,int r) {//寻找中位数的中位数 if(l==r) return a[l]; int i=0,n=0; for(int i=l;i<r-5;i+=5) { Insert_Sort(a,i,i+4); //每5个数按升序排列 n=i-l; swap(a[l+n/5],a[i+2]); //将找到的中位数放在数组a的前面 } //处理剩余元素 int res=r-i+1; if(res>0) { Insert_Sort(a,i,i+res-1); n=i-l; swap(a[l+n/5],a[i+res/2]); } n/=5; //a[0..n]存放本趟分组的中位数 if(n<=1) return a[l]; //当中位数小于2个(下标n<=1)时直接返回较小的 return Find_mid(a,l,l+n); //大于2个时递归继续寻找中位数 } int Find_pos(int a[],int l,int r,int mid) {//找到中位数的中位数在a中的下标 for(int i=l;i<=r;i++) if(a[i]==mid) return i; return -1; } int Partion(int a[],int l,int r,int pos) {//进行划分过程 swap(a[pos],a[l]); //将找到的中位数的中位数(即mid)换到数组a的最前面 int i=l,j=r; int pivot=a[l]; while(i<j) { while(i<j&&a[j]>=pivot) j--; a[i]=a[j]; while(i<j&&a[i]<=pivot) i++; a[j]=a[i]; } a[i]=pivot; return i; //返回pivot(即mid值)的下标 } int BFPTR(int a[],int l,int r,int k) { int mid=Find_mid(a,l,r); //寻找中位数的中位数 int pos=Find_pos(a,l,r,mid); //找到中位数的中位数在a中的下标 int i=Partion(a,l,r,pos); int m=i-l+1; //m即为mid归位后在a中的位置 if(m==k) return a[i]; if(m>k) return BFPTR(a,l,i-1,k); return BFPTR(a,i+1,r,k-m); } int main() { while(cin>>n) { for(int i=0;i<n;i++) cin>>a[i]; cin>>k; cout<<"The "<<k<<" number in the array is:"<<BFPTR(a,0,n-1,k)<<endl; for(int i=0;i<n;i++) cout<<a[i]<<" "; cout<<endl; } return 0; } /* 输入: 10 2 1 3 9 8 0 5 6 4 7 5 输出: The 5 number in the array is:4 0 1 3 2 4 5 6 7 8 9 */