最小堆的粗略学习

       其实堆就是一个特殊的完全二叉树(当然,所有用堆的题目都可以用线段树解决吐舌头,堆分最小堆和最大堆,我们这里先介绍最小堆。

定义

       最小堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。

构造:

   先一个个输入元素key【i】,将其构造成一个二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。

for(int i=1;i<=n;i++)
{
cin>>key[i];
up(i);

}

然而up是什么呢?详情请见代码

void up(int k)
{
int fa=k/2;
if (fa>0)
{
if (key[fa]>key[k])   //如果父亲节点大于儿子节点就交换
{
swap(key[fa], key[k]);
up(fa);
}
}

}

这么我们的堆就建好了!

大家可以试试下面的程序。

#include<bits/stdc++.h>
using namespace std;
int key[100001],n;
void up(int k)
{
int fa=k/2;
if(fa>0)
{
if(key[fa]>key[k])
{
swap(key[fa],key[k]);
up(fa);
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>key[i];
up(i);
}
for(int i=1;i<=n;i++)
{
cout<<key[i]<<" ";
}
return 0;

}





我们接下来就要对堆做删除(弹出)操作了。

献上一道练习题。

大根堆是堆的两种形式之一。根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为最大堆,又称大顶堆。大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值。现在,你需要编写一个程序,实现堆的一些操作。
输入格式
第一行是一个正整数n,代表接下来有n(n<=10^5)个操作。接下来n行。每行的格式为"pop"或者"push x",其中"pop"代表将堆顶元素输出,并删除堆顶元素。"push x"代表将一个正整数x(1<=x<=10^9)插入到堆中。

输出格式
输出每次对应pop的值,如果堆为空,则输出"empty",否则输出相应的值,每个值占一行。
样例输入
5
push 3
push 5
pop
pop
pop
样例输出
5
3
empty






















pop操作很简单,push更是简单,我就直接上代码了:

#include<bits/stdc++.h>
using namespace std;
int key[100001],n,q=0;
void up(int k)
{
int fa = k / 2;
if (fa > 0)
{
if (key[fa] < key[k])
{
swap(key[fa], key[k]);
up(fa);
}
}
}
void down(int k)
{
int son = k * 2;
if (son <= q)
{
if (son + 1 <= q) 
if (key[son] < key[son+1]) 
son = son + 1;
if (key[son] > key[k])
{
swap(key[son], key[k]);
down(son);
}
}
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++)
{
string w;
cin>>w;
if(w=="push")
{
cin >> key[++q];
up(q);//维护这个堆
}
else
{
if(q==0)
{
cout<<"empty"<<endl;
}
else
{
cout << key[1] << endl;//输出栈顶元素(即最小值)
key[1] = key[q--];//将最后一个数提到最前面,q--,然后再维护这个堆,实现了pop操作
down(1);
}
}
}
return 0;

}

谢谢大家!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值