堆与堆排序

news2024/11/28 6:34:47

一.什么是堆?

1.堆是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满。


2.堆分为两类,大根堆和小根堆。

大根堆每个结点都大于等于它的两个子结点,这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定,跟二叉查找树是有区别的。

小根堆则是小于等于它的两个子结点。

二.堆的实现

堆通常用数组来实现

具体方法就是讲二叉树的结点按照层级顺序放入数组中,根结点在位置1,它的子节点在位置2和3,而子节点的子节点则分别在位置4,5,6,7,以此类推。

上面这张图是从1开始的,但是我习惯从0开始(因为数组的索引一般是从0开始)。

这样的话如果一个父结点的下标为i,则它的父结点的位置为i/2,而它的2i+1和2i+2。这样,在不适用指针的情况下,我们也可以通过计算数组的索引在堆中上下移动。

三.堆的基本操作【上滤,下滤,建堆】

1.下滤

只有树的根元素破坏了堆序性。

我们将破坏堆序性的元素与他的最大子结点比较,如果小于他的最大子结点,如果小于他的最大子结点,则与之交换,持续比较交换,直到该元素大于他的子节点为止,或者移动到底部为止,此时该树就成功地被调整成一个大根堆。我们把根结点向下调整的操作称为下滤,很容易看出复杂度为logN。

2.上滤

只有树的最后一个元素破坏了堆序性。

同理让它和它的父元素比较,若大于父节点则交换,直到无法上移为止。

这个操作主要用于插入新元素到堆中。复杂度也为logN。

3.建堆

如果有一个乱序的数组,怎么操作让它整理为堆呢?

有两种方法,一种方法为自顶向下建堆法,对应的操作为上滤。

【1】自顶向下建堆法

方法:插入堆->上滤

【2】自下向上建堆法

方法:对每个父结点进行下滤

四.堆排序及实现步骤

1. 构造堆(如果要从小到大则构造大顶堆,否则小顶堆)

2.得到堆顶元素,这个值就是最大值

3.交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到了合适的位置

4.对堆顶的元素进行上滤操作,重新让除了最后一个元素的剩余元素中的最大值放到堆顶。

5.重复2-4步骤,直到堆中剩一个元素为止。

示例代码:将一个数组从小到大排序:

#include <iostream>
using namespace std;

// 调整大顶堆的函数
void heapify(int arr[], int n, int i) {
    int largest = i;    // 初始化最大元素为根节点
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    // 如果左子节点比根节点大,则更新最大元素的索引
    if (left < n && arr[left] > arr[largest])
        largest = left;

    // 如果右子节点比当前最大元素大,则更新最大元素的索引
    if (right < n && arr[right] > arr[largest])
        largest = right;

    // 如果最大元素不是根节点,则交换根节点和最大元素的位置
    if (largest != i) {
        swap(arr[i], arr[largest]);

        // 继续调整以确保新的子树也满足大顶堆的性质
        heapify(arr, n, largest);
    }
}

// 堆排序函数
void heapSort(int arr[], int n) {
    // 构建初始的大顶堆,从最后一个非叶子节点开始
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // 依次将堆顶元素(最大值)与数组末尾元素交换,并重新调整堆
    for (int i = n - 1; i > 0; i--) {
        swap(arr[0], arr[i]);    // 将当前最大值放到数组末尾
        heapify(arr, i, 0);      // 重新调整堆,排除已排序的部分
    }
}

// 输出数组元素的辅助函数
void printArray(int arr[], int n) {
    for (int i = 0; i < n; ++i)
        cout << arr[i] << " ";
    cout << endl;
}

// 测试堆排序算法
int main() {
    int arr[] = {9, 3, 7, 5, 1, 6, 8, 2, 4};
    int n = sizeof(arr) / sizeof(arr[0]);

    cout << "原始数组:" << endl;
    printArray(arr, n);

    heapSort(arr, n);

    cout << "排序后的数组:" << endl;
    printArray(arr, n);

    return 0;
}

如果从大到小排序,只要将构造大顶堆的函数改为构造小顶堆即可:

// 调整小顶堆的函数
void heapify(int arr[], int n, int i) {
    int smallest = i;    // 初始化最小元素为根节点
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    // 如果左子节点比根节点小,则更新最小元素的索引
    if (left < n && arr[left] < arr[smallest])
        smallest = left;

    // 如果右子节点比当前最小元素小,则更新最小元素的索引
    if (right < n && arr[right] < arr[smallest])
        smallest = right;

    // 如果最小元素不是根节点,则交换根节点和最小元素的位置
    if (smallest != i) {
        swap(arr[i], arr[smallest]);

        // 继续调整以确保新的子树也满足小顶堆的性质
        heapify(arr, n, smallest);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1096587.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++位图,布隆过滤器

本期我们来学习位图&#xff0c;布隆过滤器等相关知识&#xff0c;以及模拟实现&#xff0c;需求前置知识 C-哈希Hash-CSDN博客 C-封装unordered_KLZUQ的博客-CSDN博客 目录 位图 布隆过滤器 海量数据面试题 全部代码 位图 我们先来看一道面试题 给 40 亿个不重复的无符号…

scratch时间游戏 2023年9月中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析

目录 scratch时间游戏 一、题目要求 1、准备工作 2、功能实现 二、案例分析

EtherCAT报文-FPWR(配置地址写)抓包分析

0.工具准备 1.EtherCAT主站 2.EtherCAT从站&#xff08;本文使用步进电机驱动器&#xff09; 3.Wireshark1.EtherCAT报文帧结构 EtherCAT使用标准的IEEE802.3 Ethernet帧结构&#xff0c;帧类型为0x88A4。EtherCAT数据包括2个字节的数据头和44-1498字节的数据。数据区由一个或…

芯片学习记录TLP184

TLP184 芯片介绍 TLP184是一款光耦隔离器&#xff0c;它的主要特点包括&#xff1a;高电压耐受能力、高传输速度、高共模隔离能力、低功耗等。它可以用于工业自动化、通信设备、家用电器等领域的电气隔离应用。由一个光电晶体管组成&#xff0c;光学耦合到两个红外发射二极管…

[初始java]——规范你的命名规则,变量的使用和注意事项,隐式转化和强制转化

目录 一、标识符是么 二、命名规则 三、变量 1.定义变量的完整格式&#xff1a; 2.变量的分类 3.变量在内存中的位置 4.注意事项&#xff1a; 四、隐式转化和强制转化 五、表达式和语句的概念 一、标识符是么? 就是给类、变量、方法起名字的&#xff0c;用于标识它们。…

内网、外网、宽带、带宽、流量、网速之间的区别与联系

一.带宽与宽带的区别是什么&#xff1f; 带宽是量词&#xff0c;指的是网速的大小&#xff0c;比如1Mbps的意思是一兆比特每秒&#xff0c;这个数值就是指带宽。 宽带是名词&#xff0c;说明网络的传输速率速很高 。宽带的标准各不相同&#xff0c;最初认为128kbps以上带宽的就…

从0开始学Java:Java基础语法

文章目录 1. 注释2. 关键字&#xff08;*Keyword*&#xff09;3. 标识符( Identifier)4. 常量&#xff08;*Constant*&#xff09;5. 输出语句6. 变量&#xff08;*Variable*&#xff09;7. 计算机如何存储数据7.1 进制7.2 计算机存储单位7.3 二进制数据存储 8. 数据类型8.1 数…

一行 Python 代码搞定训练分类或回归模型

引言 自动机器学习(Auto-ML)是指自动化数据科学模型开发流水线的组件。AutoML 减少了数据科学家的工作量&#xff0c;并加快了工作流程。AutoML 可用于自动化各种流水线组件&#xff0c;包括数据理解&#xff0c;EDA&#xff0c;数据处理&#xff0c;模型训练&#xff0c;超参数…

C++11(lambda表达式)

目录 一、lambda表达式的引入 二、语法格式 三、捕捉方式 四、lambda表达式的底层 1、仿函数的调用 2、lambda的调用 ​编辑 一、lambda表达式的引入 在之前&#xff0c;我们调用函数的方式有&#xff1a;通过函数指针调用&#xff0c;仿函数也能像函数一样调用。而在C…

pgsl基于docker的安装

1. 有可用的docker环境 &#xff0c;如果还没有安装docker&#xff0c;则请先安装docker 2. 创建pg数据库的挂载目录 mkdir postgres 3. 下载pg包 docker pull postgres 这个命令下载的是最新的pg包&#xff0c;如果要指定版本的话&#xff0c;则可以通过在后面拼接 :versio…

12 | JPA 的审计功能解决了哪些问题

Auditing 指的是什么&#xff1f; Auditing 是帮我们做审计用的&#xff0c;当我们操作一条记录的时候&#xff0c;需要知道这是谁创建的、什么时间创建的、最后修改人是谁、最后修改时间是什么时候&#xff0c;甚至需要修改记录……这些都是 Spring Data JPA 里面的 Auditing…

【LeetCode刷题(数据结构)】:给定一个链表 返回链表开始入环的第一个节点 如果链表无环 则返回 NULL

给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos…

【Eclipse】查看版本号

1.在Eclipse的启动页面会出现版本号 2. Eclipse的关于里面 Help - About Eclipse IDE 如下图所示&#xff0c;就为其版本 3.通过查看readme_eclipse.html文件

华为浏览器风险提示 - 解决方案

问题 使用华为手机自带的华为浏览器时&#xff0c;可能会遇到网页提示风险提示且无法打开的情况&#xff0c;如下图。这是因为华为浏览器开启了安全浏览功能&#xff0c;下文介绍解决方案。 解决方案 取消华为浏览器设置中的安全浏览功能即可&#xff0c;操作步骤如下。打开…

EtherCAT报文-FPRD(配置地址读)抓包分析

0.工具准备 1.EtherCAT主站 2.EtherCAT从站&#xff08;本文使用步进电机驱动器&#xff09; 3.Wireshark1.EtherCAT报文帧结构 EtherCAT使用标准的IEEE802.3 Ethernet帧结构&#xff0c;帧类型为0x88A4。EtherCAT数据包括2个字节的数据头和44-1498字节的数据。数据区由一个或…

数据结构-表、树、图

一、表 1.1、散列表 也叫哈希表&#xff0c;把数据分散在列表中&#xff0c;依赖于数组下标访问的特性&#xff0c;数组的一种拓展。 散列思想&#xff1a; 即映射思想&#xff0c;用键值对来保存信息&#xff0c;键&#xff08;key&#xff09;和值&#xff08;value&a…

E117-经典赛题-主机发现与信息收集

任务实施: E117-经典赛题-主机发现与信息收集 任务环境说明&#xff1a; 服务器场景&#xff1a;p9_bt5-1&#xff08;用户名&#xff1a;root&#xff1b;密码&#xff1a;toor&#xff09; 服务器场景操作系统&#xff1a;Back Track five kali Linux 192.168.32.1…

【C++11】

目录 一、列表初始化1.1&#xff5b;&#xff5d;初始化1.2 std::initializer_list 二、声明2.1auto2.2decltype2.3nullptr 三、STL的变化四、右值引用和移动4.1左值引用与右值引用4.2右值引用的场景和意义4.3完美转发4.4完美转发的某个应用场景 四、lambda4.1lambda表达式4.2l…

Zabbix监控系统与部署Zabbix5.0监控(系列操作完整版)

Zabbix监控系统与部署Zabbix5.0监控&#xff08;系列操作完整版&#xff09; 1、监控软件的作用2、Zabbix基本介绍2.1Zabbix是什么&#xff1f;2.2Zabbix监控原理2.3Zabbix的优点2.4Zabbix的缺点2.5Zabbix监控系统的监控对象 3、Zabbix的监控架构3.1server-client架构3.2server…

EtherCAT报文-APRD(自动增量读)抓包分析

0.工具准备 1.EtherCAT主站 2.EtherCAT从站&#xff08;本文使用步进电机驱动器&#xff09; 3.Wireshark1.EtherCAT报文帧结构 EtherCAT使用标准的IEEE802.3 Ethernet帧结构&#xff0c;帧类型为0x88A4。EtherCAT数据包括2个字节的数据头和44-1498字节的数据。数据区由一个或…