堆——中位數


·今天考試這題因為小數點問題少了三十分,一開始這題用的暴力做的(就是為了騙分還沒騙到┏┛墓┗┓),好吧wsl

 

·題目內容

1.Background
雖然CZR數學很爛,但是他還是想證明一下自己的數學能力,今天他
想要表演一下瞬間計算中位數.
2.Description
一開始集合為空,每次有兩個操作:
1 x:告訴CZR當前集合中再加入一個數x.
2 :詢問CZR當前集合的中位數是多少.
·題目來源:山東濟南集訓2019.8考試題二的第三題

·算法堆頂堆

·算法實現輔助STL

·算法介紹

使用兩個堆,大根堆維護較小的值,小根堆維護較大的值

即小根堆的堆頂是較大的數中最小的,大根堆的堆頂是較小的數中最大的

將大於大根堆堆頂的數(比所有大根堆中的元素都大)的數放入小根堆,小於等於大根堆堆頂的數(比所有小根堆中的元素都小)的數放入大根堆

那么就保證了所有大根堆中的元素都小於小根堆中的元素

於是我們發現對於大根堆的堆頂元素,有【小根堆的元素個數】個元素比該元素大,【大根堆的元素個數-1】個元素比該元素小;

同理,對於小跟堆的堆頂元素,有【大根堆的元素個數】個元素比該元素小,【小根堆的元素個數-1】個元素比該元素大;

那么維護【大根堆的元素個數】和【小根堆的元素個數】差值不大於1之后,元素個數較多的堆的堆頂元素即為當前中位數;(如果元素個數相同,那么就是兩個堆堆頂元素的平均數,本題不會出現這種情況)

根據這兩個堆的定義,維護方式也很簡單,把元素個數多的堆的堆頂元素取出,放入元素個數少的堆即可。

 

·本題思路

只要維護兩個堆:
一個大根堆,保存的是集合中小的一半的數字;
一個小根堆,保存的是集合中大的一半的數字.
這樣子每次加一個數就只要保持堆的大小差距在1之內就可以了.
中位數就是某一個堆頂或者兩個堆頂的中位數.

·板子:

#include <cstdio>
#include <queue>

using namespace std;

priority_queue <int, vector<int>, less<int> > mnh;
priority_queue <int, vector<int>, greater<int> > mxh;

inline void insert_mx(int x) {
	mxh.push(x);
}

inline void insert_mn(int x) {
	mnh.push(x);
}

inline int pop_mx() {
	int tmp = mxh.top();
	mxh.pop();
	return tmp;
}

inline int pop_mn() {
	int tmp = mnh.top();
	mnh.pop();
	return tmp;
}

int T;
int op, x;
int ans;
int tot_size;

int main() {
	//freopen("mid.in", "r", stdin);
	//freopen("mid.out", "w", stdout);
	scanf("%d\n", &T);
	while (T--) {
		scanf("%d", &op);
		if (op == 1) {
			++tot_size;
			scanf("%d", &x);
			insert_mx(x);
			while (mxh.size() && mnh.size() && mnh.top() > mxh.top()) {
				x = pop_mx(), insert_mn(x);
				x = pop_mn(), insert_mx(x);
			}
			//將大於大根堆堆頂的數(比所有大根堆中的元素都大)的數放入小根堆,
			//小於等於大根堆堆頂的數(比所有小根堆中的元素都小)的數放入大根堆。 
			while (mxh.size() > (tot_size / 2))
				x = pop_mx(), insert_mn(x);
			while (mxh.size() < (tot_size / 2))
				x = pop_mn(), insert_mx(x);
				//保證大根堆大小等於總大小一半.
                //小根堆大小≤大根堆大小+1&&小根堆大小≥大根堆大小
                //想法原因:對於大根堆的堆頂元素,
				          //有【小根堆的元素個數】個元素比該元素大,
				          //【大根堆的元素個數-1】個元素比該元素小; 
		}
		if (op == 2) {
			if (tot_size % 2 == 1) {
				printf("%d\n", mnh.top());
			} else {
				ans = mnh.top() + mxh.top();
				if (ans % 2 == 1)
					printf("%d.5\n", ans >> 1);
				else
					printf("%d\n", ans >> 1);
			}
		}
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
} 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM