查找中位数(分治策略)

问题描述

设计与实现查找数组的中项问题的算法;

解决思路

要找出一个数组的中位数,最简单的方法当然是将数组排序,但快速排序的时间复杂度也需要O(nlogn),我们可以寻找更快的算法来解决。首先对于一个长度为n的有序数组a[n],若n为偶数,则中位数为(a[n/2]+a[n/2-1])/2,若n为奇数,则中位数为a[n/2],那么问题的关键就是找到a[n/2]和a[n/2-1],然而这是在有序数组中的,那么换到无序的数组中,我们可以把问题转换为求数组中第n/2大的和第n/2+1的数,再一般点就是求一个无序数组中第k大的数。那么如何求第k大的数呢,我们可以先在数组中取一个值value,将数组划分为小于value的small,等于value的equal,大于value的big三个部分,分别记三个部分的元素个数为numS、numE、numB,若k<=numS,则说明我们要找的数就在small中,若numS<k<=numS+numE,则说明我们要找的值在equal中,而又因为equal中的值都相等,因此我们要找的值就等于equal中元素的值,若k>numS+numE,则我们要找的数就在big中;在一趟比较完成之后,若我们没有得到我们需要的值,只得到了我们需要的数所在的范围,那么我们可以再对得到的small或big再使用以上算法,直到得到需要的值。

算法描述

选择数组中第k大的数的算法流程图如下:
在这里插入图片描述

算法代码

int selectK(int a[], int length, int k)  
{  
	    int *small = new int[length];  
	    int *equal = new int[length];  
	    int *big = new int[length];  
	    int value = a[0];  
	    int numS = 0, numE = 0, numB = 0;  
	    for (int i = 0; i < length; i++)  
	    {  
	        if (a[i] < value)  
	        {  
	            small[numS] = a[i];  
	            numS++;  
	        }  
	        else if (a[i] == value)  
	        {  
	            equal[numE] = a[i];  
	            numE++;  
	        }  
	        else  
	        {  
	            big[numB] = a[i];  
	            numB++;  
	        }  
	    }  
	    if (k <= numS)return selectK(small, numS, k);  
	    else if (k > numE + numS)return selectK(big, numB, k-numS-numE);  
	    else return value;  
}  

int main()
{
	srand((int)time(0));
	int n;
	cin >> n;
	int *array = new int[n];
	for (int i = 0; i < n; i++)
	{
		array[i] = rand()%10000;
	}
	cout << endl;
	cout << "中位数是:";
	if (n % 2 == 0) 
		cout << (float)(selectK(array, n, n / 2) + selectK(array, n, n / 2 + 1)) / 2 << endl;
	else
		cout << selectK(array, n, n / 2 + 1) << endl;
	delete[] array;
	system("pause");
	return 0;
}

算法分析

以下是本算法与快速排序的耗时对比:

数据规模n本算法快速排序
10001ms1ms
100002ms2ms
1000007ms28ms
100000060ms1396ms
100000004537ms14353ms

在这里插入图片描述

  • 29
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值