思路:利用最大堆,最小堆
1、将数据平分给两个堆(平分时,因为会有奇偶差,所以两个堆的元素数量之差最大只能是1);
2、采用奇偶插入,当容器中已插入元素(最大堆、最小堆数量之和)数量为偶数时,新元素插入最小堆,奇数时,新元素插入最大堆;
3、因为需要两个堆顶元素来确定中位数,那么最小堆的元素都要比最大堆的元素要大(最小堆堆顶为该段最小值,最大堆堆顶为该段最大值),所以在偶数插入时,如果该元素比最大堆的堆顶元素小(比最大堆中的一些元素大),那么将堆顶元素取出插入至最小堆;奇数插入时,类似;
4、当容器元素数量为偶数时,两个堆的堆顶元素即中位数;如果为奇数,因为刚开始容器为偶数(0),所以最小堆最终会比最大堆多出一个元素,所以最小堆堆顶即为中位数。
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
template<class T>class DynamicArray
{
private:
vector<T>m_min;
vector<T>m_max;
public:
void insert(T num)
{
if (((m_min.size() + m_max.size()) & 1) == 0)
{//容器元素偶数时,如果该值比最大堆的堆顶值小,那么先插入最大堆,然后将最大堆中的堆顶值插入最小堆,否则直接插入最小堆
if (m_max.size() > 0 && num < m_max[0])
{
m_max.push_back(num);
push_heap(m_max.begin(), m_max.end(), less<T>());
num = m_max[0];
pop_heap(m_max.begin(), m_max.end(), less<T>());
m_max.pop_back();
}
m_min.push_back(num);
push_heap(m_min.begin(), m_min.end(), greater<T>());
}
else
{//容器元素奇数时,如果该值比最小堆的堆顶值大,那么先插入最小堆,然后将最小堆中的堆顶值插入最大堆,否则直接插入最大堆
if (m_min.size() > 0 && m_min[0] < num)
{
m_min.push_back(num);
push_heap(m_min.begin(), m_min.end(), greater<T>());
num = m_min[0];
pop_heap(m_min.begin(), m_min.end(), greater<T>());
m_min.pop_back();
}
m_max.push_back(num);
push_heap(m_max.begin(), m_max.end(), less<T>());
}
}
T getMedian()
{
int size = m_max.size() + m_min.size();
if (size == 0)throw std::exception("无");
T Median = 0;
if ((size & 1) == 1)
Median = m_min[0];
else
Median = (m_min[0] + m_max[0]) / 2;
return Median;
}
};
int main()
{
DynamicArray<int> D;
D.insert(5);
D.insert(1);
D.insert(3);
D.insert(6);
cout << D.getMedian();
cin.get();
return 0;
}