C++大顶堆和小顶堆

  • 原理
    • 大顶堆
    • 小顶堆
    • 大顶堆和小顶堆对比图
    • 大顶堆和小顶堆的实现代码
  • vector和push_heap、pop_heap实现堆
    • 建堆
    • 调整堆
  • priority_queue实现堆
    • 简述
    • 模板参数
    • 成员函数
    • 大顶堆和小顶堆

原理

  堆数据结构是一种数组对象,它可以被视为一颗完全二叉树结构(或者也有可能是满二叉树)

大顶堆

  根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大顶堆。大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值。

小顶堆

  根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者,称为小顶堆。小根堆要求根节点的关键字既小于或等于左子树的关键字值,又小于或等于右子树的关键字值。

大顶堆和小顶堆对比图

大顶堆和小顶堆的实现代码

heap.h

#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;template<class T>
struct Less
{bool operator()(const T& left, const T& right) const{return left < right;}
};template<class T>
struct Greater
{bool operator()(const T& left, const T& right) const{return left > right;}
};template<class T, class Compare = Less<T>>
class Heap
{public:Heap()//无参的构造函数(系统不会给无参构造函数),开始堆是空的不需要做什么事{}Heap(T* a, size_t n){_a.reserve(n);//开空间for (size_t i = 0; i < n; ++i){_a.push_back(a[i]);}//建堆,找最后一个非叶子节点for (int i = (_a.size() - 2) / 2; i >= 0; --i)//不用size_t,因为i在这可能等于0,用size_t会死循环{AdjustDown(i);}}//向下调整void AdjustDown(int root){Compare com;int parent = root;size_t child = parent * 2 + 1;//默认为左孩子while (child < _a.size()){//选出小孩子//if (child+1 > _a.size() && _a[child + 1]< _a[child])if (child + 1 < _a.size() && com(_a[child + 1], _a[child])){++child;}//if (_a[child] < _a[parent])if (com(_a[child], _a[parent])){swap(_a[child], _a[parent]);//交换值parent = child;child = parent * 2 + 1;}else{break;}}}//向上调整void AdjustUp(int child){Compare com;int parent = (child - 1) / 2;while (parent >= 0){//if (_a[child] < _a[parent])if (com(_a[child], _a[parent])){swap(_a[parent], _a[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}//最后插入void Push(const T&x){_a.push_back(x);AdjustUp(_a.size() - 1);}//删除最大数void Pop(){assert(!_a.empty());swap(_a[0], _a[_a.size() - 1]);_a.pop_back();AdjustDown(0);}//取顶元素T& Top(){assert(!_a.empty());return _a[0];}size_t Size(){return _a.size();}bool Empty(){return _a.empty();}private:vector<T> _a;};

main.cpp

#include <iostream>
#include "heap.h"
using namespace std;int main()
{int a[] = { 10,11,13,12,16,18,15,17,14,19 };// Heap<int,Greater<int>> hp1(a,sizeof(a)/sizeof(a[0])); 最大堆// Heap<int,Less<int>> hp1(a,sizeof(a)/sizeof(a[0])); 最小堆Heap<int> hp1(a, sizeof(a) / sizeof(a[0])); // 缺省,最小堆hp1.Push(15);system("pause");return 0;
}

vector和push_heap、pop_heap实现堆

建堆

vector<int> nums = {9, 6, 2, 4, 7, 0, 1, 8, 3, 5};

如何使用nums构建最大堆

make_heap(nums.begin(), nums.end());
//或
make_heap(nums.begin(), nums.end(), less<int>());

如何使用nums构建最小堆

make_heap(nums.begin(), nums.end(), greater<int>());

调整堆

当使用上述的make_heap()建完堆后,如果vector使用push_back()插入数据或pop_back()删除数据后,会破坏最大堆/最小堆的性质,所以需要调整堆,常用push_heap()和pop_heap()两个方法。
1、push_heap()用法是,vector先push_back(),后push_heap()

nums.push_back(10);
push_heap(nums.begin(), nums.end(), less<int>());

2、pop_heap()用法是,先pop_heap(),vector后pop_back()

pop_heap(nums.begin(), nums.end(), less<int>());
nums.pop_back();

为什么pop_heap()的用法要反过来呢?
要从我们的目的来考虑,使用pop_heap()的绝大部分目的是要把堆顶元素pop出堆中,因为它最大或最小。如果先用vector的pop_back(),它删除的不是堆顶元素(nums[0]),而是vector的最后一个元素。可见这不是我们想要的结果:对于最大堆,最后一个元素既不是最大,也不一定是最小;对于最小堆,最后一个元素既不是最小,也不一定是最大。pop出来没有意义。
观察pop_heap()对堆做了什么?
pop_heap()把堆顶元素放到了最后一位,然后对它前面的数字重建了堆。这样一来只要再使用pop_back()把最后一位元素删除,就得到了新的堆。

priority_queue实现堆

priority_queue
对于这个模板类priority_queue,它是STL所提供的一个非常有效的容器。
作为队列的一个延伸,优先队列包含在头文件 中。

简述

优先队列时一种比较重要的数据结构,它是有二项队列编写而成的,可以以O(log n) 的效率查找一个队列中的最大值或者最小值,其中是最大值还是最小值是根据创建的优先队列的性质来决定的。

模板参数

优先队列有三个参数,其声明形式为:

priority_queue< type, container, function >

这三个参数,后面两个可以省略,第一个不可以。其中:
**type:**数据类型;
**container:**实现优先队列的底层容器;
**function:**元素之间的比较方式;
对于container,要求必须是数组形式实现的容器,例如vector、deque,而不能使list。
在STL中,默认情况下(不加后面两个参数)是以vector为容器,以 operator< 为比较方式,所以在只使用第一个参数时,优先队列默认是一个最大堆,每次输出的堆顶元素是此时堆中的最大元素。

成员函数

假设type类型为int,则:

  1. bool empty() const 返回值为true,说明队列为空;
  2. int size() const 返回优先队列中元素的数量;
  3. void pop() 删除队列顶部的元素,也即根节点;
  4. int top() 返回队列中的顶部元素,但不删除该元素;
  5. void push(int arg) 将元素arg插入到队列之中。

大顶堆和小顶堆

#include <functional>//构造一个空的优先队列(此优先队列默认为大顶堆)
priority_queue<int> big_heap;
//另一种构建大顶堆的方法
priority_queue<int,vector<int>,less<int> > big_heap2; //构造一个空的优先队列,此优先队列是一个小顶堆
priority_queue<int,vector<int>,greater<int> > small_heap;

C++大顶堆和小顶堆相关推荐

  1. 堆排序之 大顶堆和小顶堆 c语言

    百度得到的堆定义如下: 堆的定义如下:n个元素的序列{k1,k2,ki,-,kn}当且仅当满足下关系时,称之为堆. (ki <= k2i,ki <= k2i+1)或者(ki >= k ...

  2. 谈谈堆排序,大顶堆,小顶堆

    目录 1.前言 2.使用堆的原因 3.堆的特点 4.堆和普通树的区别 5.堆排序的过程 6.堆排序的代码实现 来源: jianshu.com/p/15a29c0ace73 1.前言 堆是一种非线性结构 ...

  3. NO29、最小的K个数(应该记住大顶堆和小顶堆的区别与联系,并不难)

    29.最小的K个数 应该记住大顶堆和小顶堆的区别与联系,并不难 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 示例1 输入 ...

  4. 堆排序:大顶堆和小顶堆 + 前K个高频元素

    堆 一.堆排序 小顶堆 举个栗子 大顶堆 二.前K个高频元素 思路分析 三.构造器代码解析 一.堆排序 要了解大顶堆和小顶堆,我们先简单了解一下堆排序. 堆排序(Heapsort)是指利用堆这种数据结 ...

  5. 堆排序(浅谈大顶堆与小顶堆)

    什么是堆? 堆是一种非线性结构,(本篇随笔主要分析堆的数组实现)可以把堆看作一个数组,也可以被看作一个完全二叉树,通俗来讲堆其实就是利用完全二叉树的结构来维护的一维数组,按照堆的特点可以把堆分为大顶堆 ...

  6. 大顶堆和小顶堆-java

    一.大顶堆和小顶堆的原理 1.大顶堆 根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大顶堆.大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值. 2.小 ...

  7. c语言标准模板小顶堆,堆排序(大顶堆、小顶堆)----C语言

    堆排序 之前的随笔写了栈(顺序栈.链式栈).队列(循环队列.链式队列).链表.二叉树,这次随笔来写堆 1.什么是堆? 堆是一种非线性结构,(本篇随笔主要分析堆的数组实现)可以把堆看作一个数组,也可以被 ...

  8. 大顶堆,小顶堆——排序问题

    如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. 例如, [2 ...

  9. 用Java实现二叉堆、大顶堆和小顶堆

    先了解了解 什么是二叉堆 二叉堆就是完全二叉树,或者是靠近完全二叉树结构的二叉树.在二叉树建树时采取前序建树就是建立的完全二叉树.也就是二叉堆.所以二叉堆的建堆过程理论上讲和前序建树一样. 什么是大顶 ...

最新文章

  1. 深入Jetty源码之HTTP协议
  2. 【IMOOC学习笔记】多种多样的App主界面Tab实现方法(二)
  3. 新浪短链api java_php调用新浪短链接API的方法
  4. canvas 绘制跟随鼠标移动的线条
  5. linux查看密码配置文件,如何在Linux上查看和配置密码时效
  6. JZOJ__Day 3:【NOIP普及模拟】排序(sort)
  7. Cortex-A7 MPCore 架构详细介绍(九种运行模式、内核寄存器组R0~R15,有特定的名字和功能)
  8. Go-Mutex互斥量
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的学校教务查询系统
  10. Sphinx/Coreseek 4.1 跑 buildconf.sh 一个错误,无法生成configure档
  11. textarea只允许上下调节尺寸
  12. 系统动力学仿真软件Vensim下载
  13. Windows 10 安装 Oracle 10g
  14. SAP 财务-统驭科目
  15. U盘所有文件(夹)变成.exe文件的解决方法
  16. FPGA控制TDC-GPX2时间间隔测量(一)
  17. Android逆向分析案例——某点评APP登陆请求数据解密
  18. ios 扫码枪外设 键盘模式_iPadOS 显威力,苹果 iPad Pro 终于用上带触控板的外接键盘...
  19. 【题解】JZOJ1321:灯
  20. ac3音频 机顶盒播放音量变小问题

热门文章

  1. 嵌入式C开发中编程模型——重点事件驱动和表驱动
  2. 长春理工大学第十四届程序设计竞赛(重现赛)
  3. MAC上安装brew
  4. VC如何制作用IC卡读卡器读取系统
  5. BlackBerry 9900通过 中国银行卡检测中心SWP-NFC通讯认证
  6. 【PCIe 5.0 - 101】SR-IOV【2】
  7. 这个夏天,我在网上学日语
  8. 如何利用系统OA进行企业员工人事档案管理
  9. android自定义adapter(实现对按钮的监听)
  10. 【Proteus仿真】【51单片机】竞赛抢答器设计