题目要求不要用STL。所以需要自己实现priority_queue, STL的是用堆实现的,仿造之。。。例如最大堆可以实现top为最大值的priority_queue。最大堆的特点就是根节点永远比子节点值大,(左右节点谁比较大都无所谓)具体就是用一个数组,每次push一个数,先放在当前数组的最后面,(所以需要一个记录队列个数的e变量),然后通过一个upd操作把它换到合适的位置,因为根于子节点是x与2*x 或2 *x + 1的关系,所以知道e,即当前节点的数组下标可以知道它的根节点下标,如果子比父大,则swap两个的值,然后递归调用。而pop操作,则先把a[1]赋值为a[e], (于是a[1]就相当于没有了,注意a[1]是队列首位,而不能是a[0]), 然后需要把a[1]调整到合适位置,需要一个down操作,父亲如果左右儿子中的较大的那个小,则交换,然后递归调用。注意down和upd操作都有边界,分别是e和1,下标不能超过这两个。由于,swap,upd,down,只需要在这个类生成的时候调用,所以可以写成私有的内联函数,此外,我还写了个公有的show,方便调试,可以忽略。我实现的时候e是最后一个元素的下一个空位子的下标,和上面说的有点矛盾,将就看吧。第一次实现,刚学的类。。比较挫,不知道会不会过系统测试,现在貌似还不能提交(会SE),以后再交吧。
因为题目既要最大值也要最小值,所以写了两个,一个pq,一个mqp,即一个top是最大值,另一个是最小值。
代码如下:
头文件:
class pqueue{
int *a, e;
void swap(int &x, int &y){
x = x + y;
y = x - y;
x = x - y;
}
void down(int x){
if (a[x] < a[2 * x] && 2 * x < e) {
swap(a[x], a[2 * x]);
if (e > 2 * x) down(2 * x);
}
if (a[x] < a[2 * x + 1] && 2 * x + 1 < e){
swap(a[x], a[2 * x + 1]);
if (e > 2 * x + 1) down(2 * x + 1);
}
}
void upd(int x){
if (x > 1){
if (a[x] > a[x >> 1])
{
swap(a[x], a[x >> 1]);
if ((x >> 1) > 1) upd(x >> 1);
}
}
}
public :
void pop(void);
void push(int x);
void create(int x);
int top(void);
void clear(void);
void show(void);
};
class mpqueue{
int *a, e;
void swap(int &x, int &y){
x = x + y;
y = x - y;
x = x - y;
}
void down(int x){
if (a[x] > a[2 * x] && 2 * x < e) {
swap(a[x], a[2 * x]);
if (e > 2 * x) down(2 * x);
}
if (a[x] > a[2 * x + 1] && 2 * x + 1 < e){
swap(a[x], a[2 * x + 1]);
if (e > 2 * x + 1) down(2 * x + 1);
}
}
void upd(int x){
if (x > 1){
if (a[x] < a[x >> 1])
{
swap(a[x], a[x >> 1]);
if ((x >> 1) > 1) upd(x >> 1);
}
}
}
public :
void pop(void);
void push(int x);
void create(int x);
int top(void);
void clear(void);
void show(void);
};
函数实现:
#include"pqueue.h"
#include<iostream>
#include<cstring>
#include<cstdlib>
void pqueue :: pop(void){
a[1] = a[--e];
down(1);
}
void pqueue :: push(int x){
a[e] = x;
upd(e++);
}
int pqueue :: top(void){
return a[1];
}
void pqueue :: create(int x){
a = (int *) malloc(4 * x * sizeof (int));
memset(a, 0, sizeof(a) * 4 * x);
e = 1;
}
void pqueue :: clear(void){
free(a);
a = NULL;
e = 1;
}
void pqueue :: show(void){
for (int i = 1; i < e; ++i) std :: cout << a[i] << ' ';
std :: cout << std :: endl;
}
#include"mpqueue.h"
#include<iostream>
#include<cstring>
#include<cstdlib>
void mpqueue :: pop(void){
a[1] = a[--e];
down(1);
}
void mpqueue :: push(int x){
a[e] = x;
upd(e++);
}
int mpqueue :: top(void){
return a[1];
}
void mpqueue :: create(int x){
a = (int *) malloc(4 * x * sizeof (int));
memset(a, 0, sizeof(a) * 4 * x);
e = 1;
}
void mpqueue :: clear(void){
free(a);
a = NULL;
e = 1;
}
void mpqueue :: show(void){
for (int i = 1; i < e; ++i) std :: cout << a[i] << ' ';
std :: cout << std :: endl;
}
主程序:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include"pqueue.h"
#include"mpqueue.h"
#pragma warning (disable : 4996)
#define N 10000005
using namespace std;
pqueue a;
mpqueue b;
int main(){
int n, x, i, j, k, tem, re;
while (scanf("%d", &n), n){
a.create(N), b.create(N);
for (i = 0, re = 0; i < n; ++i){
scanf("%d", &x);
for (j = 0; j < x; ++j){
scanf("%d", &tem);
a.push(tem);
b.push(tem);
}
/*a.show(), b.show();*/
re += a.top() - b.top();
a.pop(), b.pop();
/*a.show(), b.show();*/
}
a.clear(), b.clear();
printf("%d\n", re);
}
return 0;
}
就是这样啦,其实重载运算符也可以把最大变成最小,但是mqp与pq代码其实一模一样,只改了两个小于号,(改成大于)所以就不用重载运算符了。
是不是写的太挫了?(最近刚学类,不要鄙视。。。)另外,STL中的pq是动态长度的,但是我不会动态变长度,所以只能用malloc开一个做够大的了。(其实一开始是想对每天malloc一下的,后来不知道该怎么把它们连起来就放弃了,直接开了10000005,不知道会不会RE,有没有其他好的方法,防止这种情况,比较简单的实现随时变长的功能?求指教)