关于堆的一切

这篇具有很好参考价值的文章主要介绍了关于堆的一切。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前置知识

首先给出堆的定义:
堆是一颗树,满足堆的性质,即:
对于一个节点,它的权值大于(或小于)它的各个儿子的权值

有这个性质,显然
堆的根节点权值是整个堆中最大或最小的
由此可分为小根堆大根堆

二叉堆

最常见的堆就是二叉堆
二叉堆是一颗满足堆的性质完全二叉树
显然,二叉堆的子树也是二叉堆

接下来,我们以小根堆为例:

当一个节点权值小于其父亲时,我们尝试不断将这个节点与父亲交换,直到其满足堆的性质
这就是向上调整

同理,
当一个节点权值大于其父亲时,我们尝试不断将这个节点与其两个儿子中权值较小的一个交换,直到其满足堆的性质
这就是向下调整

为什么这里要与权值较小的一个交换呢?
因为我们要使交换后满足堆的性质
所以新的父节点权值应小于它的两个儿子

由于堆的高度为 \(\log{n}\)
所以以上两个操作复杂度显然为 \(\mathcal {O}(\log{n})\)

那么有了这两个操作我们就可以完成:
插入(新建节点然后向上调整)
查询最大(最小)值(根节点权值)
删除最大(最小)值(与末尾节点交换,再向下调整)
删除任意节点(与末尾交换,再向上或向下调整,见代码)
修改任意节点权值(向上或向下调整)

Luogu (模板)堆

#include<bits/stdc++.h>

using namespace std;

static constexpr int AwA = 1e6 + 10;

inline static int Read() {
    int res = 0;
    bool flag = false;
    int c = getchar();
    while ((c < '0' || c > '9') && ~c) {
        flag |= c == '-';
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        res = (res << 1) + (res << 3) + (c ^ 48);
        c = getchar();
    }
    return flag ? -res : res;
}

//这里我们认为一个节点的父亲是u<<1,左儿子为u>>1,右儿子为u>>1|1
//根为1
//由堆为完全二叉树的性质可得只需开一倍数组
int val[AwA];
//储存总节点数
int len;

inline void MoveUp(int u) {
    while (u >> 1) {
        int fa = u >> 1;
        if (val[fa] <= val[u]) break;
        swap(val[fa], val[u]);
        u = fa;
    }
}

inline void MoveDown(int u) {
    while (u << 1 <= len) {
        int son = u << 1;
        if (son < len && val[son | 1] < val[son]) son |= 1;
        if (val[u] <= val[son]) break;
        swap(val[u], val[son]);
        u = son;
    }
}

inline int GetTop() { return val[1]; }

inline void Pop() {
    swap(val[1], val[len]);
    len--;
    MoveDown(1);
}

inline void Push(int _val) {
    val[++len] = _val;
    MoveUp(len);
}

//删除任意已知节点
inline void Delete(int u) {
    swap(val[u], val[len]);
    len--;
    if (val[u << 1] <= val[u]) MoveDown(u);
    else MoveUp(u);
}

//每次对于根进行向下调整,来合并左右儿子代表的两个堆
//OIwiki上有证明,这种建树是O(n)的
inline void Build(int _len, const int *a) {
    len = _len;
    memcpy(val + 1, a + 1, sizeof(int) * len);
    //叶子节点不调整,减小常数
    for (int i = (len >> 1) - 1; i; i--) MoveDown(i);
}

int main() {
    int n = Read();
    while (n--) {
        int op = Read();
        if (op == 1) Push(Read());
        else if (op == 2) printf("%d\n", GetTop());
        else Pop();
    }
    return 0;
}

此外,对于这段代码,我们来仔细讨论一下:

inline void Build(int _len, const int *a) {
    len = _len;
    memcpy(val + 1, a + 1, sizeof(int) * len);
    for (int i = (len >> 1) - 1; i; i--) MoveDown(i);
}

这段代码可以在 \(\mathcal {O}(n)\) 时间内建堆
我们按照节点bfs序倒序向下调整
每当调整到一个节点时
该节点的左右儿子所在子树已然是二叉堆
这时再把根节点向下调整满足堆的性质
可视为左右儿子代表的二叉堆的合并

证明:
待补充

可并堆

待补充文章来源地址https://www.toymoban.com/news/detail-839335.html

其他堆

待补充

到了这里,关于关于堆的一切的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于差分约束的一切

    本文使用 CC BY-NC-SA 4.0 许可 。 本文为笔者在 OI 学习中的复习向学习笔记。 部分内容会比较简略。 如有好的习题会不断补充。 差分约束 解决这样一类问题: 给定一个 n 元一次不等式组,让你求出一组解/判定是否有解/算出某个数的最值/算出和的最值…… 先从最简单的开始

    2024年04月09日
    浏览(40)
  • 关于基环树的一切

    本文使用 CC BY-NC-SA 4.0 许可 。 本文为笔者在 OI 学习中的复习向学习笔记。 部分内容会比较简略。 如有好的习题会不断补充。 基环树 是一个有 (n) 个点 (n) 条边的连通图。 因为 树 有 (n) 个点 (n-1) 条边。 所以基环树可以看作是加了一条边的树。 那么也就是 加了个环的

    2024年04月08日
    浏览(31)
  • 关于树的直径的一切

    本文使用 CC BY-NC-SA 4.0 许可 。 本文为笔者在 OI 学习中的复习向学习笔记。 部分内容会比较简略。 如有好的习题会不断补充。 以下部分详细证明可见 OI Wiki 。 树的直径 指树上任意两点间距离的最大值。 先以任意点为根找到最远点 (v) 。 再以 (v) 为根找到最远点 (u) 。

    2024年04月08日
    浏览(44)
  • 【算法】关于排序你应该知道的一切(下)

    和光同尘_我的个人主页 单程孤舟,出云入霞,如歌如吟。 --门孔 啊还是国庆快乐!上节介绍了较为简单的插入排序、选择排序,今天我们上强度,学习交换排序、归并排序还有计数排序,开冲😎 2.1.1. 基本思想 关于冒泡排序我们在C语言的学习中就有涉及 依次比较序列中相

    2024年02月07日
    浏览(43)
  • 【算法】关于排序你应该知道的一切(上)

    和光同尘_我的个人主页 单程孤舟,出云入霞,如歌如吟。 --门孔 国庆快乐!!本来想把排序都做到一起的,才写了一半就八千多字了,那就分开发吧,一如既往的详细哦⌨️ 排序 :所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来

    2024年02月06日
    浏览(35)
  • 【数据结构】关于排序你应该知道的一切(下)

    和光同尘_我的个人主页 单程孤舟,出云入霞,如歌如吟。 --门孔 啊还是国庆快乐!上节介绍了较为简单的插入排序、选择排序,今天我们上强度,学习交换排序、归并排序还有计数排序,开冲😎 2.1.1. 基本思想 关于冒泡排序我们在C语言的学习中就有涉及 依次比较序列中相

    2024年02月05日
    浏览(37)
  • 我们所知道的关于 OpenAI 的 ChatGPT 的一切

    如果您还没有听说过ChatGPT,这是来自人工智能实验室 OpenAI 的不可思议的新聊天机器人,这里是您需要了解的有关这个有争议的新程序的所有信息的快速入门。 ChatGPT 是一种人工智能工具,允许用户生成原始文本。你可以问它问题,给它创造性的提示,并用它来生成一大堆不

    2023年04月13日
    浏览(41)
  • JUC前置知识

    JUC概述 在开发语言中,线程部分是重点,JUC是关于线程的。JUC是java.util.concurrent工具包的简称。这是一个处理线程的工具包,JDK1.5开始出现的。 线程和进程 线程和进程的概念 进程(process): 是计算机的程序关于某数据集合上的一次允许活动,是操作系统进行资源分配和任务调

    2024年02月08日
    浏览(43)
  • (一) AIGC了解+前置知识

    大论文双盲意见还没回来,每天度日如年,慌的一批,唯恐延毕,得找点事情干~ 小论文major revision,本来打算一鼓作气把小论文完全改好的,但是搞了三个月的文字工作,好久没有吸收新知识了 所以…每天边学新东西,边改小论文~ 最近AIGC比较火,就从它开始吧 AIGC大致了解

    2024年02月13日
    浏览(32)
  • 7.前置知识3:LoadBalance

    https://medium.com/google-cloud/understand-cloud-load-balancer-like-a-senior-engineer-d4f55f3111fc 负载均衡本来是个硬件设备。其实一开始确实是的,然而现在已经不同了。 尤其是云厂商提供的负载均衡方案几乎全部是靠软件。现在的负载均衡不仅是网络流量复杂均衡,几乎所有的平衡多个计算资

    2024年02月20日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包