双堆求中位数及C实现

本文介绍了使用双堆求中位数的算法,包括算法描述、C语言实现以及测试程序和结果。算法通过创建一个小根堆和大根堆,动态维护中位数,确保堆的大小至少为数据量的一半。遍历数据时,根据数值大小插入相应堆,保持堆平衡。最后,根据两个堆的元素个数确定中位数。

堆的动态创建与删除可参考http://blog.youkuaiyun.com/pngynghay/article/details/22101359,此处不再赘述。

双堆求中位数

算法描述:

1、创建两个堆(一个小根堆、一个大根堆),堆大小至少为给定数据个数的一半,(size+1)/2,即向上取整;

2、假定变量mid用来保存中位数,取定第一个元素,赋值给mid,即作为初始的中位数;

3、依次遍历后面的每一个数据,如果比mid小,则插入大根堆;否则插入小根堆;

4、如果大根堆和小根堆上的数据个数相差为2,则将mid插入到元素个数较少的堆中,然后从元素个数较多的堆中删除根节点,并将跟节点赋值给mid;

5、重复步骤3和4,直到所有的数据遍历结束;

此时,mid保存了一个数,再加上两个堆中保存的数,就构成了给定数据的集合。

如果两个堆中元素个数相等,则mid即为最终的中位数;否则,元素较多的堆的根节点元素与mid的和求平均值,即为最终的中位数。

算法实现

算法实现采用了整数,所以,最终的结果取了整数,可以将返回值转换为浮点型,更精确。

uint32_t getmedian(uint32_t *array, uint32_t size)
{
	int i = 0, minelem = 0, maxelem = 0;
	uint32_t mid = array[0];
	uint32_t heapsize = (size+1)/2;
	heap_t *minheap = heap_malloc(heapsize);
	heap_t *maxheap = heap_malloc(heapsize);
	for(i = 
### 中位数的定义与解方法 中位数是指一组有序数据中间位置上的数值。如果数据的数量为奇数,则中位数是位于中间的那个数;如果是偶数,则中位数是中间两个数的平均值。 #### 使用结构实现动态中位数计算 为了高效地维护并查询中位数,可以采用双堆(最大和最小)的方式[^2]: - **最大**:存储较小的一半数据,其根节点始终保存这一部分的最大值。 - **最小**:存储较大的一半数据,其根节点始终保存这一部分的最小值。 通过这种方式,可以在 $O(\log n)$ 的时间内完成插入操作,并在常数时间 $O(1)$ 获取当前的中位数。 以下是基于 C++ 实现的一个例子: ```cpp #include <iostream> #include <queue> using namespace std; class MedianFinder { public: priority_queue<int> maxHeap; // 大顶,存小的那一半数 priority_queue<int, vector<int>, greater<int>> minHeap; // 小顶,存大的那一半数 /** 添加一个数字 */ void addNum(int num) { if (maxHeap.empty() || num <= maxHeap.top()) { maxHeap.push(num); } else { minHeap.push(num); } // 调整两大小平衡 if (maxHeap.size() > minHeap.size() + 1) { minHeap.push(maxHeap.top()); maxHeap.pop(); } else if (minHeap.size() > maxHeap.size()) { maxHeap.push(minHeap.top()); minHeap.pop(); } } /** 查找中位数 */ double findMedian() { if (maxHeap.size() == minHeap.size()) { return (maxHeap.top() + minHeap.top()) / 2.0; } else { return maxHeap.top(); // 奇数情况下返回大顶的顶部元素 } } }; int main() { MedianFinder mf; int nums[] = {1, 3, 5, 7, 9}; for(auto& num : nums){ mf.addNum(num); cout << "Current median is: " << mf.findMedian() << endl; } } ``` 上述代码实现了 `addNum` 和 `findMedian` 方法来分别处理新增加的数据以及获取当前的中位数。这种方法适用于实时更新场景下的中位数查找问题。 对于静态数组的情况,可以通过先对数组排序再选取相应位置的值作为中位数。例如,在已知长度的情况下可以直接定位到中心点或者取均值[^1]。 ### 静态数组中的中位数计算实例 下面是一个简单的C语言程序用于演示如何在一个固定大小的数组上找到其中位数: ```c #include <stdio.h> #include <stdlib.h> void sortArray(int *arr, int size) { qsort(arr, size, sizeof(int), (int(*)(const void*, const void*))strcmp); } double getMedian(int sortedArr[], int length) { if(length % 2 != 0) return (double)sortedArr[length/2]; else return ((double)(sortedArr[(length-1)/2]+sortedArr[length/2])/2.0; } int main(){ int data[5]={4,8,6,2,10}; int len=sizeof(data)/sizeof(data[0]); sortArray(data,len); printf("The median value is %.2lf\n",getMedian(data,len)); return 0; } ``` 此段代码首先利用标准库函数qsort对输入数组进行了升序排列,之后依据数组长度判断是否需要计算单个还是多个元素构成的中位数
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值