最大堆/最大优先队列——算法题

课程作业的Online Judge有一道算法题:
Description

The mall is running a T-day promotion.

·Every day, customers who shop at the mall can put their own receipts into a box to participate in the promotion.

·Every day after the mall closes, the manager will take out the receipt with the maximum amount in the box and the lucky customer’s spending WILL BE PAID BY THE MALL.

·If there are more than one maximums in the box, only one of them can be selected randomly.

·Every day the rest receipts will remain in the event box until the end of the promotion.

·Test data promise the box will never be empty during these days.

We need your help to figure out how much the mall pay for the promotion.

Input
The first line contains an integer T, 1 ≤ T ≤ 100,000, the number of days of the promotion.

Each of the following T lines contains a sequence of non-negative integers separated by whitespace.

The numbers in the (i+1)-st line give the data for the i-th day.

The first number in each of these lines, n, 0 ≤ n ≤ 50, is the number of receipts and the subsequent n numbers are positive integers of the bill amounts.

No receipt is bigger than 50,000.

Output
The total amount paid to the customers.

Sample Input 1

5
3 1 2 2
2 1 1
4 10 5 5 1
0
1 2

Sample Output 1

24

做题的过程中犯了一些错误:

  • c++可以用&来调用参数,改变参数值,但是C语言里面不可以,要用指针传递参数地址才行。我没有用指针,而是在函数外部加需要修改的部分。
  • 没有compile error,出现runtime error,助教说原因是数组越界,我在本地编译器上跑,没有输入数据就结束了,显示“(进程 11216)已退出,代码为 -1073741571”,在数组前面加了static,然后就解决了,原因是栈的默认内存空间为1M左右,数组定义的太大了,所以会导致内存溢出。
    (https://www.cnblogs.com/gousheng/p/7850367.html)OJ系统错误提示
  • 左孩子和右孩子写错了(从0开始计数)
    int left = k * 2 + 1;//左孩子
	int right = k *2 + 2;//右孩子
	int parent = (k - 1)/2;//父母
  • 在写最大堆调整的函数时,写错了。
    错误的:
void HeapAdjust(int* a, int heap_size, int k)
//假设指标为k 的根节点下面的已经是最大堆,但k节点自己小于其孩子,对此进行调整
{
	int left = k * 2 + 1;//左孩子
	int right = k  * 2+2;//右孩子
	int l,tmp;
    l=k;
	if (left<heap_size && a[left]>a[k]) {
		l = left;
	}
	if (right<heap_size && a[right]>a[k]) {
		l = right;               //这里错了
	}
	if (l != k) {
	    tmp = a[k];
		a[k] = a[l];
		a[l] = tmp;
		HeapAdjust(a, heap_size,l);
	}
}

正确的:

void HeapAdjust(int* a, int heap_size, int k)
//假设指标为k 的根节点下面的已经是最大堆,但k节点自己小于其孩子,对此进行调整
{
	int left = k * 2 + 1;//左孩子
	int right = k  * 2+2;//右孩子
	int l,tmp;
    l=k;
	if (left<heap_size && a[left]>a[k]) {
		l = left;
	}
	if (right<heap_size && a[right]>a[l]) {
		l = right;                //这才对了
	}
	if (l != k) {
	    tmp = a[k];
		a[k] = a[l];
		a[l] = tmp;
		HeapAdjust(a, heap_size,l);
	}
}

我在OJ系统上提交的代码:

#include
#include

//以下的堆,都是最大堆,数组从0开始
void HeapInsert(int a[], int heap_size, int key);
void HeapAdjust(int* a, int heap_size, int k);
void HeapBuild(int* a, int heap_size);
int HeapMax(int* a, int heap_size);

void HeapInsert(int a[], int heap_size, int key)
//heap_size是没有插入之前堆的大小,插入之后也不改变,要手动加1
{
	int k = heap_size;
	while (k > 0 ) {
		if((k-1)/2<0) break;
		if(a[(k - 1) / 2] >= key) break;
		a[k] = a[(k - 1) / 2];
		k = (k - 1) / 2;
	}
	a[k] = key;
}

void HeapAdjust(int* a, int heap_size, int k)
//假设指标为k 的根节点下面的已经是最大堆,但k节点自己小于其孩子,对此进行调整
{
	int left = k * 2 + 1;//左孩子
	int right = k  * 2+2;//右孩子
	int l,tmp;
    l=k;
	if (left<heap_size && a[left]>a[k]) {
		l = left;
	}
	if (right<heap_size && a[right]>a[l]) {
		l = right;
	}
	if (l != k) {
	    tmp = a[k];
		a[k] = a[l];
		a[l] = tmp;
		HeapAdjust(a, heap_size,l);
	}
}
void HeapBuild(int* a, int heap_size) 
//建堆
{
	//从底层开始维护,k的父母是(k-1)/2向下取整,堆的最后一个元素的父母是heapsize/2-1
	for (int i = heap_size / 2 - 1; i >= 0; i--) {
		HeapAdjust(a, heap_size, i);
	}
}

int HeapMax(int* a, int heap_size)
//取出最大的元素,也就是根结点,然后维护成最大堆
{
	int max;
	max = a[0];
	a[0] = a[heap_size - 1];
	HeapAdjust(a, heap_size-1, 0);
	return max;
}

int main() 
{
	int T, n,key, size=0,i,j;//size为目前累计账单数,也就是heap_size
	long  sum = 0;//获奖账单累计金额
	static int a[50000000]={0};
	scanf("%d", &T);

	//先用第一组数据建一个最大堆
	scanf("%d", &n);
	for ( i = 0; i < n; i++) {
		scanf("%d", &a[i]);
	}
	size = n;
	HeapBuild(a, size);
	sum += HeapMax(a, size);
	size--;

	for ( i = 1; i < T; i++) {
		scanf("%d", &n);
		for ( j = 0; j < n; j++) {
			scanf("%d", &key);
			HeapInsert(a, size, key);
			size++;
		}
		sum += HeapMax(a, size);
    	size--;
	
	}
	printf("%ld\n", sum);
	return 0;
}

不知道为什么,我把这段代码复制粘贴到vc++6.0,然后用助教给的数据测试,答案是错的。反正OJ系统 Accept 就行,以后再看。这样一个问题竟然做了两三天,真头大,继续加油 !

(写代码时参考了:https://www.cnblogs.com/Nastukashii/p/4394307.html)

你可能感兴趣的:(算法基础,算法)