1.堆介绍

「堆 heap」是一种满足特定条件的完全二叉树,主要可分为图 8-1 所示的两种类型。

  • 「大顶堆 max heap」:任意节点的值

    其子节点的值。
  • 「小顶堆 min heap」:任意节点的值

    其子节点的值。

堆作为完全二叉树的一个特例,具有以下特性。

最底层节点靠左填充,其他层的节点都被填满。

我们将二叉树的根节点称为“堆顶”,将底层最靠右的节点称为“堆底”。

对于大顶堆(小顶堆),堆顶元素(即根节点)的值分别是最大(最小)的。

2.使用优先级队列(priority_queue)创建和维护堆

2.1 概念

堆(heaps) 是一种特殊的数据组织方式,STL 中的 priority_queue 容器适配器底层就是采用堆来组织数据存储的。

实际上,堆通常用作实现优先队列,大顶堆相当于元素按从大到小顺序出队的优先队列。从使用角度来看,我们可以将“优先队列”和“堆”看作等价的数据结构。因此,这里对两者不做特别区分,统一使用“堆“来命名。

2.2 实例

C++标准库中的 std::priority_queue 是一种用于创建和维护堆的容器适配器。它提供了一种方便的方式来实现堆数据结构,通常用于处理具有优先级的元素。以下是使用 std::priority_queue 来创建和维护堆的使用介绍:

  1. 包含头文件

    #include <queue>
  2. 创建优先队列

    std::priority_queue<int> maxHeap; // 创建一个最大堆,默认情况下是最大堆
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap; // 创建一个最小堆
    std::priority_queue <int,vector<int>,less<int> > maxHeap;//创建一个最大堆
    • 你可以创建一个最大堆(默认情况),或者通过提供第二个参数为 std::vector 和第三个参数为 std::greater 来创建一个最小堆。
  3. 插入元素

    使用 push 方法将元素插入堆中,堆会自动维护其性质。

    maxHeap.push(10);
    minHeap.push(5);
  4. 访问堆顶元素

    使用 top 方法可以访问堆顶元素,即最大值(最大堆)或最小值(最小堆)。

    int max = maxHeap.top();
    int min = minHeap.top();
  5. 移除堆顶元素

    使用 pop 方法可以移除堆顶元素,堆会自动维护其性质

    maxHeap.pop(); // 移除最大堆顶元素
    minHeap.pop(); // 移除最小堆顶元素
  6. 检查堆是否为空

    使用 empty 方法可以检查堆是否为空。

    bool isMaxHeapEmpty = maxHeap.empty();
    bool isMinHeapEmpty = minHeap.empty();
  7. 获取堆中元素的数量

    使用 size 方法可以获取堆中元素的数量。

    int maxHeapSize = maxHeap.size();
    int minHeapSize = minHeap.size();
  8. 自定义比较函数

    如果你需要自定义比较函数来定义元素之间的比较规则,可以在创建优先队列时提供自定义比较函数。

    struct Compare {
    bool operator()(int a, int b) {
    // 自定义比较规则
    return a > b; // 创建最小堆
    }
    }; std::priority_queue<int, std::vector<int>, Compare> customHeap;

    在上述例子中,我们创建了一个自定义的比较函数 Compare,它定义了创建一个最小堆。

std::priority_queue 简化了堆的创建和维护,特别适用于需要按优先级访问元素的问题,如任务调度、Dijkstra算法等。你可以根据问题的要求选择最大堆或最小堆,并通过提供自定义比较函数来实现更复杂的比较规则。

3.使用make_heap等系列函数创建和维护堆

3.1 概念

在C++中,make_heappush_heappop_heapsort_heap 是用于操作堆的四个标准库算法。这些算法用于处理堆数据结构,它们可以帮助你创建、维护和排序堆。以下是它们的用途和用法:

3.2 具体函数

  1. make_heap:([]中内容可省略)

    • 用途:make_heap 用于将一个范围内的元素转化为一个堆,默认是大顶堆(通常是最大堆或最小堆)。
    • 语法:make_heap(first, last,[less<>()/greater<>()]):([]中内容可省略)),其中 firstlast 分别是范围的起始迭代器和结束迭代器。

      其中第三个参数是less<>()或是greater<>(),前者用于生成大顶堆,后者用于生成小顶堆,第三个参数默认情况下为less<>(),less()用于生成大顶堆。
    • 示例:
    vector<int> nums = {3, 1, 4, 1, 5, 9, 2};
    display(nums);
    make_heap(nums.begin(), nums.end());
    display(nums);
    // nums 现在是一个最大堆,最大值 9 在根节点
    结果:
    (原数组)3 1 4 1 5 9 2
    (现数组)9 5 4 1 1 3 2
  2. push_heap

    • 用途:push_heap 用于将新元素添加到堆中,同时维护堆的性质。(确保已有的元素序列是一个有效的堆,否则请先使用make_heap创建堆)
    • 语法:push_heap(first, last,[less<>()/greater<>()]),其中 firstlast 定义了一个范围,范围内的元素是一个堆,且在 firstlast - 1 之间添加了一个新元素。第三个参数同上。
    • 示例:
    vector<int> nums = {3, 1, 4, 1, 5};
    display(nums);
    make_heap(nums.begin(), nums.end());
    display(nums);
    nums.push_back(9);
    push_heap(nums.begin(), nums.end());
    display(nums);
    // nums 现在是一个最大堆,最大值 9 在根节点 结果:
    3 1 4 1 5(原先)
    5 3 4 1 1(建堆后)
    9 3 5 1 1 4(插入新元素后)
  3. pop_heap

    • 用途:pop_heap 用于将(确保已有的元素序列是一个有效的堆,否则请先使用make_heap创建堆)的根节点(通常是最大值或最小值)取出,并将其放在范围的末尾,然后维护剩余元素的堆性质(对前n - 1个元素调用make_heap()函数)。
    • 语法:pop_heap(first, last,[less<>()/greater<>()]),其中 firstlast 定义了一个范围,范围内的元素是一个堆。第三个参数同上
    • 示例:
    vector<int> nums = {9, 1, 4, 1, 5};
    display(nums);
    make_heap(nums.begin(), nums.end());
    display(nums);
    pop_heap(nums.begin(), nums.end());
    display(nums);
    // nums 现在是一个最大堆,最大值 9 被移至范围末尾
    结果展示:
    9 1 4 1 5(原先)
    9 5 4 1 1(建堆后)
    5 1 4 1 9(移出一个元素出堆,注意这里的9只是移到了最后,并没有去除)
  4. sort_heap

    • 用途:sort_heap 用于对一个(确保已有的元素序列是一个有效的堆,否则请先使用make_heap创建堆)进行排序,将堆中的所有元素按升序排列(小根堆)。
    • 语法:sort_heap(first, last,,[less<>()/greater<>()]),其中 firstlast 定义了一个范围,范围内的元素是一个堆。第三个参数同上。
    • 示例:
    vector<int> nums = {9, 1, 4, 1, 5};
    display(nums);
    make_heap(nums.begin(), nums.end());
    display(nums);
    sort_heap(nums.begin(), nums.end());
    display(nums); 结果展示:
    9 1 4 1 5(原先)
    9 5 4 1 1(建堆后)
    1 1 4 5 9(排序后)

这些堆算法对于处理堆数据结构非常有用,可以在各种算法和数据结构中使用。堆通常用于实现优先队列和解决一些最大值或最小值相关的问题。这些算法可以提高代码的可读性和效率,因为它们是经过精心设计和优化的标准库函数。

4.二者的区别和各自的优势

4.1 优先级队列优势

priority_queue 可以提供堆没有的优势,它可以自动保持元素的顺序;但我们不能打乱 priority_queue的有序状态,因为除了第一个元素,我们无法直接访问它的其他元素。如果需要的是一个优先级队列,这一点非常有用。

4.2 使用 make_heap()优势

从另一方面来说,使用 make_heap() 创建的堆可以提供一些 priority_queue 没有的优势:

1、可以访问堆中的任意元素,而不限于最大的元素,因为元素被存储在一个容器中,就像是我们自己的 vector。这也提供了偶然破坏元素顺序的可能,但是总可以调用 make_heap()来还原堆。

2、可以在任何提供随机访问迭代器的序列容器中创建堆。这些序列容器包括普通数组、string 对象、自定义容器。这意味着无论什么时候需要,都可以用这些序列容器的元素创建堆,必要时,可以反复创建。甚至还可以为元素的子集创建堆。

C++ 语法结构--堆的更多相关文章

  1. Linux程序存储结构与进程结构堆和栈的区别【转】

    转自:http://www.hongkevip.com/caozuoxitong/Unix_Linux/24581.html 红客VIP(http://www.hongkevip.com):Linux ...

  2. 04 Linux 指令语法结构与帮助命令

    一.Linux指令语法结构 [tyang3@localhost Desktop]$ command [-options] [arguments] 指令           选项           参 ...

  3. CSS_简介/语法结构/长度单位/应用方式/标签的样式重置/表单样式重置

    一.CSS简介:  w3c(World Wide Web Consortium):万维网联盟,是规定网页标准的一个组织(叫做Web标准) Web标准:是由w3c和其他标准化组织制定的一系列标准的集合, ...

  4. PHP读书笔记(1)-PHP语法结构与变量

    一 .php基础语法 1.php语法结构 标准风格:<?php code; ?>.PHP每句代码用;(分号)结尾.<---就用这个,其他的看看就可以了 短风格:<? code; ...

  5. C#中区别多态、重载、重写的概念和语法结构

    C#中区别多态.重载.重写的概念和语法结构 重写是指重写基类的方法,在基类中的方法必须有修饰符virtual,而在子类的方法中必须指明override. 格式: 基类中: public virtual ...

  6. Java初认识--Java中的语法结构

    Java中的语法结构(程序流程控制) Java的语法结构有四种: 1.顺序结构. 顺序结构很简单,就是按顺序执行,输出就可以了. 2.判断结构. 判断结构的一个代表性的语句是if:if语句有三种格式体 ...

  7. Tcl与Design Compiler (二)——DC综合与Tcl语法结构概述

    1.逻辑综合的概述 synthesis = translation + logic optimization + gate mapping . DC工作流程主要分为这三步 Translation : ...

  8. html dl dt dd标签元素语法结构与使用

    dl dt dd认识及dl dt dd使用方法 标签用于定义列表类型标签. dl dt dd目录 dl dt dd介绍 结构语法 dl dt dd案例 dl dt dd总结 一.dl dt dd认识 ...

  9. PHP基本的语法结构

    学过C语言的话,上手PHP语言就非常快了,如果你有bash shell的基础,那恭喜你,上手PHP会更快,我们先来了解一下一些比较简单的东西,界定符和注释在PHP中的写法: 一 php文档的语法结构 ...

  10. Shader的基本用法和语法结构

    Shader的基本用法和语法结构 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 Introductio ...

随机推荐

  1. awk所有常用语法

    awk [OPTIONS] PROGRAM FILE... 选项: -F 指定分隔符 -f 引用awk脚本 -v VAR=VALUE 定义一个变量传递给PROGRAM,但是这里的变量BEGIN读不了, ...

  2. 在WInform开发中实现工具栏/菜单的动态呈现

    在Winform系统开发中,为了对系统的工具栏/菜单进行动态的控制,我们对系统的工具栏/菜单进行动态配置,这样可以把系统的功能弹性发挥到极致.通过动态工具栏/菜单的配置方式,我们可以很容易的为系统新增 ...

  3. 【云原生 | Kubernetes 系列】— Kubernetes存储方案

    目录 [云原生 | Kubernetes 系列]- Kubernetes存储方案 一.基本存储 EmptyDir HostPath NFS 搭建nfs服务器 二.高级存储 PV和PVC pv pvc ...

  4. [集训队作业2013] 城市规划(NTT)

    一周一博客二专题计划 题面 n 个点的简单 (无重边无自环) 有标号无向连通图数目. 看着就很典 思路 设\(f(n)\)为n点连通图数目.设\(g(n)\)为n点不一定联通图数目,显然直接枚举每条边 ...

  5. JavaScript异步编程2——结合XMLHttpRequest使用Promise

    目录 1. 概述 2. 详论 3. 参考 1. 概述 在上一篇文章<JavaScript异步编程1--Promise的初步使用>,简单介绍了一下Promise的初步使用.复习一下,Prom ...

  6. GaussDB(for Redis)游戏实践:玩家下线行为上报

    本文分享自华为云社区<GaussDB(for Redis) 游戏实践:玩家下线行为上报>,作者:GaussDB 数据库 为保护未成年人的身心健康,2007年国家推出网络游戏防沉迷系统,对未 ...

  7. GaussDB(DWS)迁移:一种执行高效的TereData的marco迁移方案

    摘要:提供一种执行高效的TereData的marco迁移方案. 本文分享自华为云社区<GaussDB(DWS)迁移 - teredata兼容 -- macro兼容 # [玩转PB级数仓Gauss ...

  8. 【云享·人物】华为云AI高级专家白小龙:AI如何释放应用生产力,向AI工程化前行?

    摘要:AI技术发展,正由应用落地阶段向效率化生产阶段演进,AI工程化能力将会不断深入业务,释放企业生产力. 本文分享自华为云社区<[云享·人物]华为云AI高级专家白小龙:AI如何释放应用生产力, ...

  9. 华为云数据库GaussDB(for openGauss):初次见面,认识一下

    摘要:本文从总体架构.主打场景.关键技术特性等方面进行介绍GaussDB(for openGauss). 1.背景介绍 3月16日,在华为云主办的GaussDB(for openGauss)系列技术第 ...

  10. 想会用synchronized锁,先掌握底层核心原理

    摘要:synchronized锁修饰方法和代码块时底层实现上是一样的,但是在修饰方法时,不需要JVM编译出的字节码完成加锁操作,而synchronized在修饰代码块时,是通过编译出来的字节码生成的m ...