最近总有新手要问堆怎么写,我是这么想的
既然都学c++了,堆这种东西怎么能手写呢,太对不起STL了
(当然能手写的都是的大神了,这只是我懒得手打的理由)
正好之前机房有位大神将他学习的堆教给了我
我就以他讲的写一篇blog来帮助其他人吧
这里先介绍一下vector
vector是一个动态数组
当你需要多少空间时就会自动分配多少空间给你
极大的省了许多空间(通常我是拿来存图的),声明方法如下
先加头文件 #include
声明: vector<参数> 变量名 然后要什么类型就在参数里写什么类型
这里我们只需要用int就行
因为我们只需要存数字,存图时通常用结构体,详细用法自行看百度吧,
vector a
这样我们就有一个可以存放数字的动态数组a了,
接着学习几个基本操作
加入数据 : a.push_back(num)
删除最后一个数据 : a.pop_back()
队尾+1的位置 : a.end() 注意:a.end()是一个迭代器,我也不知道是什么,反正只要减去数组的名字就可以得到末尾往后的位置的下标
队首的位置 : a.begin() 这也是一个迭代器
然后就是开始了
用for循环读入数据
1
2
3
4
5
6
for(int i=1;i<=n;i++)
{
int num;
scanf(“%d”,&num);
a.push_back(num);
}
然后开始建堆
用algorithm中的三个函数就可以搞定了
先加#include
里面有一个函数为make_heap()
现在我们要把a数组变为一个堆,就这么写
1
make_heap(a.begin(),a.end(),cmp)
注意,cmp是自己添加的一个函数,返回值应该是bool
而这里的cmp很特殊
小根堆的cmp是这么写的
1
2
3
4
bool cmp(int x,int y)
{
return x>y;
}
注意,我并没有写错,就是大于号,所以才说它特殊
往后如果再推入元素需要进行维护
如果建堆的时候写了cmp这个参数,那每次都要再传入一遍
再推入的时候是这样的
先加入a数组里
a.push_back(num)
再用一个函数维护一下
push_heap(a.begin(),b.end(),cmp)
此时,a这个动态数组又变成堆了
而堆我们通常是取第一个元素,而vector的第一个元素和数组一样
直接取a[0]即可
取完a[0]以后,你可能要删掉这个堆顶的元素
删除刚好和加入相反
同样有一个函数是用来删除堆的元素的
pop_heap(a.begin(),a.end(),cmp)
注意这里还没完,它的功能只是将第一个元素放到最后,然后忽略最后一个元素的情况下再维护一遍堆
所以我们还得用a.pop_back()把最后一个元素推掉
这样堆的建立插入和删除操作就讲完了
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
vector<int> a;
int num,n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num);
a.push_back(num);
}
make_heap(a.begin(),a.end(),cmp);
scanf("%d",&num);
a.push_back(num);
push_heap(a.begin(),a.end(),cmp);
cout<<a[0]<<endl;
pop_heap(a.begin(),a.end(),cmp);
a.pop_back();
return 0;
}
也可以用priority_queue来建;
大根堆:priority_queue heap
小根堆:priority_queue