堆,实际上是一个完全二叉树,大概就是介个样子。。。
堆一般又分为大顶堆和小顶堆(实际上差不多。。。这里就用小顶堆举个例好了QwQ)
手写堆
其实STL中的优先队列已经有堆的作用了,但是手写的堆也有一些自己的优势。我们先来看看堆的一些常用操作。
1.插入一个数
2.求集合当中的最小值
3.删除最小值
4.删除任意一个元素
5.更改任意一个元素
前三个功能,都可以通过优先队列直接实现,而后面两个功能,用手写的堆更容易实现,所以。。。手写的堆,也是有优势滴QwQ
手写的堆可以用一维数组存储,虽然看起来5个功能很麻烦,但其实依赖两个函数就可以全部实现。
利用down(下沉)函数和up(上升)函数,两个函数就可以实现上面的功能。
down函数
down函数主要是为了把大的数往树的下方沉,每次比较选择子节点中较小的一个数,进行替换,模板如下
void down(int u)
{
int t = u; // t 用于找一个最小的节点值
if(u * 2 <= size && h[t] > h[u * 2]) t = u * 2; // h 用于存放堆
if(u * 2 + 1 <= size && h[t] > h[u * 2 + 1]) t = u * 2 + 1;
if(u != t)
{
swap(h[t], h[u]);
down(t); //利用递归的思想继续下沉
}
}
up函数
同样的,up函数是为了让小的数往上升,模板也更简单,以为up函数只用和根节点比较就好了
void up(int u)
{
while(u / 2 && h[u / 2] > h[u])
{
swap(h[u / 2], h[u]);
u /= 2;
}
}
几个操作的具体方法
1.插入
在数列尾部插入后上升
scanf("%d", &x);
h[++ size] = x;
up(size);
2.求最小值
也就是在 1 位置的元素
printf("%d", h[1]);
3.删除最小值
先把堆尾的元素赋值给堆首,再删除堆尾
h[1] = h[size];
size --;
down(1);
4.删除任意元素
与删除最小值差不多,但是要注意你不知到替换之后数的大小情况,所以要down一遍,再up一遍
scanf("%d", &k)
h[k] = h[size];
szie --;
up(k), down(k);
5.替换任意元素
直接赋值以后,利用两个函数,找到替换后的位子就可以了
scanf("%d%d", &k, &x);
h[k] = x;
up(k), down(k);
优先队列
优先队列,priority_queue也与堆有着相同的作用
priority_queue默认的情况是大根堆,我们有两种方法来把它变成小根堆,一种是直接输入负值,一种是在定义时就定义成小根堆,定义的方法还有一些常见的操作方法,都会在下面的代码中
priority_queue<int, vector<int>, greater<int>> q;
q.push() // 插入一个元素
q.pop() //删除一个元素
q.top() //返回堆顶的元素
优先队列属于c++中的STL,是一个语法问题,在这也不多阐述了。
这就是堆的用法,是不是好简单的。。。(其实完全不知道有什么用。。。要不是最短路用的到才不会来学QwQ)
不管了,至少也算是学会了一个新知识点。。。怎么用以后再说吧QwQ