求一个无序数组的中位数

来源:互联网 发布:2017php面试题大全 编辑:程序博客网 时间:2024/05/21 11:16

求一个无序数组的中位数。
如:{2,5,4,9,3,6,8,7,1}的中位数为5,{2,5,4,9,3,6,8,7,1,0}的中位数为4和5。
要求:不能使用排序,时间复杂度尽可能高。
提示:考虑堆或者快排思想解决。


思路一:利用堆排序的思路

将前n/2的元素放进一个大堆里,然后将后续的元素与堆顶比较,如果比堆顶大,则继续比下一个,如果比堆顶小,则与堆顶的值进行交换。

这样操作完后,堆里的元素都是比堆顶小的,不再堆里的元素都比堆顶大,则堆顶就是中位数。

参考代码如下:

void FindMid(int a[],int size){if(a == NULL ||size<1)return ;priority_queue<int> q;   //创建一个大堆for (int i = 0;i<size/2+1;++i)    //将前size/2的元素放入堆中q.push(a[i]);  int top =  q.top();for(int i = size/2+1;i<size;++i)   //将后半部分的元素一一与堆顶比较{if (a[i]<top){q.pop();q.push(a[i]);}top = q.top();}if(0==size%2)     //判断奇偶,从而判断是几个中位数{q.pop();int top1 = q.top();cout<<"中位数是"<<top<<"和"<<top1<<endl;}else{cout<<"中位数是"<<top<<endl;}}


测试代码如下:

void test(){int a[] = {2,5,4,9,3,6,8,7,1};//中位数是5int b[] = {2,5,4,9,3,6,8,7,1,0};//中位数是4和5int len = sizeof(a)/sizeof(a[0]);int lenb = sizeof(b)/sizeof(b[0]);FindMid(a,len);FindMid(b,lenb);}


结果如下:

+


思路二:利用快排的思想

任意挑一个元素,以改元素为支点,划分集合为两部分,如果左侧集合长度恰为 (n-1)/2,那么支点恰为中位数。如果左侧长度<(n-1)/2, 那么中位点在右侧,反之,中位数在左侧。 进入相应的一侧继续寻找中位点。
            这种方法很快,但是在最坏的情况下时间复杂度为O(N^2), 不过平均时间复杂度好像是O(N)。

参考代码如下:

int QucikFind(int a[],int k,int l,int r){int key = a[l];int i = l;int j = r;while (i<j){while (i<j&&a[j]>key)j--;if(i<j)a[i++] = a[j];while (i<j&&a[i]<key)i++;if(i<j)a[j--] = a[i];}a[i] = key;if (i == k)return i;else if (i>k)return QucikFind(a,k,l,i-1);elsereturn QucikFind(a,k,i+1,r);}void Find1(int a[],int size){if (a==NULL||size<1)return ;cout<<"中位数是";   if(0==size%2)    //判断奇偶 cout<<a[QucikFind(a,size/2,1,size-1)]<<"和 "<<a[QucikFind(a,size/2-1,1,size-1)]<<endl;elsecout<<a[QucikFind(a,size/2,1,size-1)]<<endl;}

测试代码如下:

int a[] = {2,5,4,9,3,6,8,7,1};//中位数是5int b[] = {2,5,4,9,3,6,8,7,1,0};//中位数是4和5int len = sizeof(a)/sizeof(a[0]);int lenb = sizeof(b)/sizeof(b[0]);Find1(a,len);Find1(b,lenb);

结果如下:





原创粉丝点击