堆(一)堆是啥子

堆?

堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
在这里插入图片描述
——选自“百度百科”

堆的特性?

  • 堆中某个节点的值总是不大于(大根堆)或不小于(小根堆)其父节点的值;
  • 堆总是一棵完全二叉树。

堆的作用?

  • 堆支持插入、删除、查找最大(小)值的操作。

堆的操作?

终于到了堆的操作了。
堆有5种操作,上移( u p up up)、下移( d o w n down down)、插入( i n s e r t insert insert)、删除( d e l e t e delete delete)、建堆。

规定:
h数组表示堆里面的值
swap函数表示把堆两个元素交换
num表示堆中元素个数

上移( u p up up

上移操作:当我们插入进来的数(一般是最后一个数)使得堆不符合特性时,我们就每次把它与它的父亲比较,然后上移;

//我们以小根堆为例:
void up(int x){//把x这个位置上移
    while (x>0&&h[x]<h[x/2]){
        swap(x,x/2);//交换
        x/=2;//very important!
    }
    return;
}
下移( d o w n down down

下移操作:当我们的堆不符合特性(一般是堆顶)时,我们就每次把它与它的儿子比较,然后下移;

//我们以小根堆为例:
void down(int x){//把x这个位置下移
    while (x*2<=num&&h[x]>h[x/2]||x*2+1<=num&&h[x]>=h[x*2+1]){
        int y=x*2;
        if (y+1<=num&&h[y]>h[y+1]) y++;//尽量选小的换
        swap(x,y);//交换
        x=y;//very important!
    }
    return;
}
插入( i n s e r t insert insert

插入操作:很多时候我们需要插入元素进堆里面,于是乎,我们就num++并把它插入到堆的最后一个位置;

void insert(int x){//插入x
    h[++num]=x;
    up(num);
    return
}
删除( d e l e t e delete delete

删除操作:很多时候我们需要删除堆里面的最大(小)值,于是乎,我们就先把堆顶弹出。
很多人就问了:弹出后不久没堆顶了吗?
不着急“孩子,慢慢来”。
这时我们就采取将最后一个元素放到堆顶,然后下移(自己感性理解一下)。

void del(int x){//删除x
    h[1]=h[num--];
    down(1);
    return
}
建堆

讲了那么久,终于到了建堆时刻了!
对于建堆,我们有两种方法:

方法一:
for (int i=1;i<=n;i++){
	scanf("%d",&x);
	insert(x);
}

时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)(很显然吧)

方法二
for (int i=1;i<=n;i++){
	scanf("%d",&h[i]);
}
for (int i=n/2;i>0;i--)
	down(i);

时间复杂度: O ( n ) O(n) O(n),感兴趣的可以自己去证明一下,嘿嘿;

总结

这篇文章就这么结束了,感谢大家的支持!下一篇我将讲关与堆的一些例题,让大家多了解堆。
我可能是为数不多的手打堆的人了,很多人都在用优先队列(感兴趣的可以自己学一下),可能是因为当年我是P党所以我才手打堆吧
如果这篇文章有问题,欢迎大家踊跃“投稿”!
哦,别忘了我的blog
下一章,堆(二)堆的应用

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值