求一个无序数组的中位数

求一个无序数组的中位数。
如:{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};//中位数是5
	int b[] = {2,5,4,9,3,6,8,7,1,0};//中位数是4和5
	int 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);
	else
		return 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;
	else
		cout<<a[QucikFind(a,size/2,1,size-1)]<<endl;
}

测试代码如下:

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

结果如下:





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值