欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

查找中位数(分治策略)

程序员文章站 2022-06-17 19:46:28
...

问题描述

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

解决思路

	要找出一个数组的中位数,最简单的方法当然是将数组排序,但快速排序的时间复杂度也需要
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 本算法 快速排序
1000 1ms 1ms
10000 2ms 2ms
100000 7ms 28ms
1000000 60ms 1396ms
10000000 4537ms 14353ms

查找中位数(分治策略)

相关标签: 算法设计与分析