挑战p72
自己总结了一下,并实现了下,原理等都写在注释之中了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define M 1009
int heap[M];
/*
堆最重要的特征在于儿子的值一定不小于父亲的值,可以相等的。
*/
int num;
/*
push的原理:
将所要插入的数值插到整个二叉树最后一层的最右边的节点中,
如果与父亲节点存在大小颠倒的情况就向上提升,并将父节点的值放下来。
直到不存在大小颠倒的情况了,就将要插入的数值插入该节点之中。
*/
void push(int x)
{
int i = num++; //自身节点的编号
while(i>0)
{
int a = (i-1)/2; //父节点的编号
if(heap[a] <= x) break; //如果没有大小颠倒了就停止提升
heap[i] = heap[a];//将父亲节点的值拉下来
i = a; //用父亲节点的编号替换此时的编号
}
heap[i] = x; //将要插入的数值插入该节点
}
/*
pop()的原理:
将堆中最后一个节点的值复制到根节点处,从上开始替换,
如果存在大小颠倒就向下交换,(注意如果有两个儿子,则选择数值较小的儿子进行交换)
直到不存在大小颠倒就停止。
*/
int pop()
{
int ret = heap[0];
int x = heap[--num];
int i = 0; //从根节点开始替换
while(i*2+1<num)
{
int a = i*2+1;//左边儿子节点
int b = i*2+2;//右边儿子节点
if(b < num && heap[b] < heap[a]) //找出较小的儿子节点
a = b;
if(heap[a] >= x) break; //不存在大小颠倒
heap[i] = heap[a]; //向下交换
i = a;
}
heap[i] = x;
return ret;
}
int main()
{
num = 0;
int n;
printf("--请输入要测试的数目:");
scanf("%d",&n);
for(int i = 0;i < n;i++)
{
int temp;
scanf("%d",&temp);
push(temp);
}
printf("此时堆中的情况:\n");
for(int i = 0;i < n;i++)
printf("%d ",heap[i]);
printf("\n");
printf("--请输入要弹出的数目:");
int m;
scanf("%d",&m);
for(int i = 0;i < m;i++)
printf("%d\n",pop());
for(int i = 0;i < n-m;i++)
printf("%d ",heap[i]);
return 0;
}