线性时间选择

来源:互联网 发布:二代身份证识别器java 编辑:程序博客网 时间:2024/05/17 21:48

给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素。


Step1. 从a[]中选取划分基准元素,将a[0:n-1]划分为2部分,得到A[0:q]:
1、a[0:q],q+1个元素,包括a[q]

2、a[q+1, n-1],n-q-1个元素

Step2. 
1、L=q+1>=k, q>=k-1, 则左半段至少有k个不大于x=a[q]的小元素,第k小的元素在左半段,递归搜索a[0:q]

2、L=q+1<k, q<k-1, 左半段比x=a[q]小的元素少于k个,x=a[q]不可能是第k小元素,第k小的元素在右半段,并且为右半段的第k-q小,递归搜索a[q+1:n-1]


为降低最坏复杂性,要求尽可能保证划分后的2个子集大小接近,相差过大将导致不平衡。

解决思路:以n(例如5)的长度将数组分割成若干小段,通过排序取到个小段的中位数,再取各中位数的中位x,以此为基准划分至少与位于左半部分的3n/10-1个元素小于x,保证划分后的子集长度相近

原题:采用线性时间选择算法,根据基站k-dist距离,挑选出
k-dist值最小的基站
k-dist第5小的基站
k-dist值第50小的基站
k-dist值最大的基站

#include<iostream>#include<string>#include<fstream>#include<cstdlib>#define max 2000using namespace std;typedef struct Basestation{int ENODEBID;float LONGITUDE;//经度 float LATITUDE;//纬度 float K_DIST ; }Basestation; Basestation a[max];int Max(int a, int b);int Partition(Basestation a[], int p, int r, Basestation z);int RandomizedPartition(Basestation a[], int p, int r);Basestation Select(Basestation a[], int p, int r, int ak);int main(){int i = 1;int num = 0;Basestation temp;ifstream file;file.open("Data_Of_Basestation.txt", ios::in);if(file.bad()){cout<<"打开文件时发生错误"<<endl;return 0;}while(!file.eof()){file>>a[i].ENODEBID>>a[i].LONGITUDE>>a[i].LATITUDE>>a[i].K_DIST;i++;num++;//cout<<a[i].ENODEBID<<" "<<a[i].LONGITUDE<<" "<<a[i].LATITUDE<<" "<<a[i].K_DIST<<endl;file.get();if(file.peek()==EOF)break;}cout<<"==============================================================================="<<endl;cout<<"\t\t\t基站编号 "<<"\t"<<" 基站经度 "<<"\t"<<" 基站纬度 "<<"\t"<<" K_DIST"<<endl; cout<<"K_DIST最小的基站是:\t";temp = Select(a, 1, num, 1);cout<<temp.ENODEBID<<"\t\t"<<temp.LONGITUDE<<"\t\t"<<temp.LATITUDE<<"\t\t"<<temp.K_DIST<<endl;cout<<"K_DIST第五小的基站是:\t";temp = Select(a, 1, num, 5);cout<<temp.ENODEBID<<"\t\t"<<temp.LONGITUDE<<"\t\t"<<temp.LATITUDE<<"\t\t"<<temp.K_DIST<<endl;cout<<"K_DIST第五十小的基站是:";temp = Select(a, 1, num, 50);cout<<temp.ENODEBID<<"\t\t"<<temp.LONGITUDE<<"\t\t"<<temp.LATITUDE<<"\t\t"<<temp.K_DIST<<endl;cout<<"K_DIST最大的基站是:\t";temp = Select(a, 1, num, num);cout<<temp.ENODEBID<<"\t\t"<<temp.LONGITUDE<<"\t\t"<<temp.LATITUDE<<"\t\t"<<temp.K_DIST<<endl;cout<<"==============================================================================="<<endl;file.close();return 0; } int Max(int a, int b){return (a>b)?a:b; }int Partition(Basestation a[], int p, int r, Basestation z)//z表示以数组中第z个为基准 {int i = p;int j = r+1;int k;Basestation beitai;for(k=p; k<=r; k++){if(a[k].K_DIST==z.K_DIST)break;}beitai = a[k];a[k] = a[p];a[p] = beitai;Basestation x = a[p];while(i<j){while (a[++i].K_DIST <x.K_DIST && i<r);   //扩展左端a[p:i],左→右搜索大元素a[i]>=x        while (a[--j].K_DIST >x.K_DIST);               //扩展右端a[j:r],左←右搜索小元素a[i]<=xif(i >= j){break;}beitai = a[i];a[i] = a[j];a[j] = beitai;}a[p] = a[j];a[j] = x;return j; }Basestation Select(Basestation a[], int p, int r, int k){Basestation beitai;Basestation final;if(r-p<20)//如果数组足够小,简单排序,寻找第k小元素 {for(int i = 0; i<r-p+1; i++){for(int j = p+1; j<=r-i; j++){if(a[j].K_DIST<a[j-1].K_DIST){beitai = a[j];a[j] = a[j-1];a[j-1] = beitai;}}}return a[p+k-1];}int s;int t;for ( int i = 0; i<=(r-p-4)/5; i++ ) {         s= p + 5*i;    t = s + 4;     for(int k=0; k<3; k++)    {    for(int j=s+1; j<=t-k; j++)    if(a[k].K_DIST<a[k-1].K_DIST)    {    beitai = a[j];a[j] = a[j-1];a[j-1] = beitai;}}       beitai = a[p+i];       a[p+i] = a[s+2];       a[s+2] = beitai;     }    final = Select(a, p, p+(r-p-4)/5, (r-p+6)/10);int i = Partition(a, p, r, final);int j = i-p+1;if(k==j)return a[i];else if(k<j)return Select(a, p, i, k);elsereturn Select(a, i+1, r, k-j);}


0 0