C++默認大小根堆priority_queue求中位數

以前實現大小根堆總要自己寫代碼,循環父節點和孩子節點比大小換位置,今天看到C++中有默認的大小根堆實現

// 大根堆
priority_queue<type> BigRoot;
// 小根堆
priority_queue<type, vector<type>, greater<type>> SmallRoot;

當然如果全是正數的話,小根堆實現比較難記可以直接存成負數。

應用
Find Median from Data Stream 找出數據流的中位數

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.
Examples:
[2,3,4] , the median is 3
[2,3], the median is (2 + 3) / 2 = 2.5
Design a data structure that supports the following two operations:
void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.

For example:
add(1)
add(2)
findMedian() -> 1.5
add(3)
findMedian() -> 2

思路
既然要求中位數,如果數據有序最好了直接索引取值就好了
那麼如何維持一個有序數據流?
1)二分插入
2)考慮把有序數組從中間切開[minpart | maxpart],維持一個大根堆存minpart和一個小根堆存maxpart,兩堆top節點必然存放有中位數
比如[4,2,3,1,5],我們希望最終大根堆存[3,2,1],小根堆存[4,5],最終返回大根堆top
存的過程爲每次新元素插入大根堆,大根堆的最大值top插入小根堆,如果小根堆size大於大根堆則把小根堆top移入大根堆
插入過程爲:

step1. 大根堆 4 小根堆 null
step2. 大根堆 2 小根堆 4
step3. 大根堆 3,2 小根堆 4
step4. 大根堆 2,1 小根堆 4,3
step5. 大根堆 3,2,1 小根堆 5,4

代碼

class MedianFinder {
public:
    void adjust(int num) {
    	minpart.push(num);
    	// 存成負數大根堆變小根堆
    	maxpart.push(-minpart.top());
    	minpart.pop();
    	if(minpart.size() < maxpart.size()) {
    		// maxpart中存的是負數,minpart中存的是正數
    		minpart.push(-maxpart.top());
    		maxpart.pop();
    	}
    }
    double findMedian() {
        return minpart.size() > maxpart.size() ? minpart.top() : 0.5 *(minpart.top() - maxpart.top());
    }

private:
    priority_queue<long> minpart, maxpart;
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章