堆排序(详解)c++

news/2025/2/25 17:48:05

堆排序 (可以⽤ ppt 演⽰流程) 堆排序(Heap Sort)是指利⽤堆这种数据结构所设计的⼀种排序算法。本质上是优化了选择排序算法,选择排序的思想是在堆排序元素中拿出最大值或最小值,然后把这个位置的值放在它该放的位置上就可以了,重复这个操作直到整个数组有序,堆排序是将数据全部放到堆这个数据结构,就能快速地找出最大值以及最小值

大家可能会想到以前学过的模拟堆的操作,给一个数组把里面全部的数放到堆里,重复拿出堆顶再删除堆顶的操作,整个数组就变得有序了,这个算法虽然能够将整个数组排成有序的,但需要额外创建一个堆,实际上堆排序是不需要创建一个堆的,因为本身有一个数组了,堆排序是先把数组调整成堆,然后再让整个数组有序,因此堆排序是不需要创建额外的堆,直接在原始数组上操作即可

堆排序的过程分两步:

  1. 建堆。升序建⼤堆,降序建⼩堆。 建堆过程,从倒数第⼀个⾮叶⼦节点开始,倒着⼀直到根结点位置,每个结点进⾏向下调整。
  2. 排序。删除堆顶的逻辑。 每次将堆顶元素与堆中最后⼀个元素交换,然后将堆顶元素往下调整。直到堆中剩余⼀个元素,所有元素就都有序了。 因此,堆排序仅需⽤到向下调整算法

第一步:建堆

  • 建堆是将待排序数组的基础上,使其变成一个堆。
  • 流程:从倒数第一个非叶子结点开始,执行向下调整算法,直到根结点。它的核心思想,就是从倒数第一个非叶子节点开始,从小堆调整到大堆,根节点开始向下调整完之后,整个数组就变成堆了

第二步:排序

  • 在大根堆的基础上,用选择排序的思想将数组调整成有序状态。
  • 流程:每次将堆顶元素与堆中最后一个元素交换,堆的大小减一,然后将堆顶元素向下调整。重复这个过程,直到堆中剩下一个元素。 

 代码:

测试链接:P1177 【模板】排序 - 洛谷

#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];

void down(int p, int len)
{
    int c = p * 2;
    while (c <= len)
    {
        if (c + 1 <= len && a[c + 1] > a[c]) ++c;
        if (a[p] >= a[c]) return;

        swap(a[p], a[c]);
        p = c;
        c = p * 2;
    }
}

void heap_sort()
{
    //1.建堆
    //最后一个节点(n)的父亲肯定是根叶节点(n/2)
    for (int i = n / 2; i >= 1; --i)
    {
        //每个节点执行向下调整算法
        down(i, n);
    }

    //2.排序
    //每次拿堆顶和最后一个元素交换
    for (int i = n; i > 1; --i) // 枚举堆里面最后一个元素的位置
    {
        swap(a[i], a[1]);
        //swap完后,大的数放到后面的有序序列,减少一个要排序的数
        //第一个参数,从哪个点开始向下调整,第二个参数,当前堆大小是多少
        down(1, i - 1); 
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    heap_sort();

    for (int i = 1; i <= n; i++) cout << a[i] << " ";

    return 0;
}

时间复杂度

时间复杂度需要计算两部分:⼀是建堆,二是排序,然后累加起来
  • 算建堆可以用错位相减法,左右两边乘公比2,下面再减去上面,变成了一个等比数列,可以用求和公式,a1*(1-q的n次方)/1-q,根据二叉树的性质代入,算出来的结果消掉低效的东西就剩下一个n了,因此整个建堆的时间复杂度是O(N)级别的
  • 排序部分的时间复杂度很好估计,每次都是从堆中选择⼀个最⼤值,与最后⼀个元素交换,再调整。⼀次选择的时间复杂度为 log(n+1) ,⼀共执⾏ n-1 次,⼤概就是 O(nlogn) 级别

http://www.niftyadmin.cn/n/5865785.html

相关文章

为什么要将PDF转换为CSV?CSV是Excel吗?

在企业和数据管理的日常工作中&#xff0c;PDF文件和CSV文件承担着各自的任务。PDF通常用于传输和展示静态的文档&#xff0c;而CSV因其简洁、易操作的特性&#xff0c;广泛应用于数据存储和交换。如果需要从PDF中提取、分析或处理数据&#xff0c;转换为CSV格式可能是一个高效…

【Day45 LeetCode】图论问题 Ⅲ

一、图论问题 Ⅲ 1、沉没孤岛 这题只能从边界开始扩散&#xff0c;将靠近边界的陆地标记&#xff0c;表示不是孤岛&#xff0c;最后将孤岛沉没&#xff0c;将不是孤岛标记回陆地。 # include<iostream> # include<vector>using namespace std;void dfs(vector&l…

ViT 模型介绍(三)——简单实战项目

用 ViT 做一个简单的图像分类任务 在 CIFAR-10 数据集上进行图像分类。通过 Hugging Face 的 transformers 库&#xff0c;加载一个预训练的 ViT 模型&#xff0c;并使用 PyTorch 进行微调。通过训练模型&#xff0c;评估测试集上的准确性&#xff0c;并可视化部分预测结果 可…

跨境宠物摄像头是一种专为宠物主人设计的智能设备

跨境宠物摄像头是一种专为宠物主人设计的智能设备&#xff0c;它结合了摄像头技术和互联网通信功能&#xff0c;使宠物主人能够远程监控和互动家中的宠物。以下是对跨境宠物摄像头的详细介绍&#xff1a; 一、主要特点 1. 远程监控&#xff1a;宠物主人可以通过手机等移动设备…

Three.js 快速入门教程【八】常见材质类型

系列文章目录 Three.js 快速入门教程【一】开启你的 3D Web 开发之旅 Three.js 快速入门教程【二】透视投影相机 Three.js 快速入门教程【三】渲染器 Three.js 快速入门教程【四】三维坐标系 Three.js 快速入门教程【五】动画渲染循环 Three.js 快速入门教程【六】相机控件 Or…

流媒体网络协议全解析:从实时传输到自适应流,如何选择最优方案?

一、历史发展与协议提出者 流媒体协议的发展与互联网技术迭代紧密相关,主要分为三个阶段: 早期专有协议(1990s-2000s) RTSP/RTP 提出者:RealNetworks(RTSP初始推动者),后由IETF标准化(RFC 2326)。背景:1996年推出,用于视频监控和点播系统,基于UDP传输媒体流,支持…

详解golang的Gengine规则引擎

一:简介 Gengine是一款基于golang和AST(抽象语法树)开发的规则引擎, Gengine支持的语法是一种自定义的DSL, Gengine通过内置的解释器对规则文件进行解析,构建规则模型,进行相应的规则计算和数据处理。Gengine于2020年7月由哔哩哔哩(bilibili.com)授权开源。Gengine现已应用…

前端学习—HTML

前端学习 html概括 HTML结构标签定义网页内容 CSS样式配置&#xff0c;规定网页布局 JavaScript编程网页行为 HTML超文本标记语言&#xff0c;是一套标记标签&#xff0c;描述网页的 XHTML是以XML格式编写的HTML HTML文档也叫web页面&#xff0c;由互相嵌套的HTML元素构…