面试题41:数据流中的中位数

思路:利用最大堆,最小堆
1、将数据平分给两个堆(平分时,因为会有奇偶差,所以两个堆的元素数量之差最大只能是1);
2、采用奇偶插入,当容器中已插入元素(最大堆、最小堆数量之和)数量为偶数时,新元素插入最小堆,奇数时,新元素插入最大堆;
3、因为需要两个堆顶元素来确定中位数,那么最小堆的元素都要比最大堆的元素要大(最小堆堆顶为该段最小值,最大堆堆顶为该段最大值),所以在偶数插入时,如果该元素比最大堆的堆顶元素小(比最大堆中的一些元素大),那么将堆顶元素取出插入至最小堆;奇数插入时,类似;
4、当容器元素数量为偶数时,两个堆的堆顶元素即中位数;如果为奇数,因为刚开始容器为偶数(0),所以最小堆最终会比最大堆多出一个元素,所以最小堆堆顶即为中位数。

#include
#include
#include 
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;
}

你可能感兴趣的:(C++剑指Offer刷题集)