数据结构——堆的应用 堆排序详解

💞💞 前言

hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹
在这里插入图片描述

💥个人主页:大耳朵土土垚的博客
💥 所属专栏:数据结构学习笔记
💥对于数据结构顺序表、链表、堆有疑问的都可以在上面数据结构的专栏进行学习哦~
有问题可以写在评论区或者私信我哦~

在土土的上篇博客二叉树堆的介绍与实现中,我们发现测试代码是升序;今天我们就来分析堆的重要应用——**堆排序**🎉🎉。

#include"Heap.h"
int main()
{Heap hp;HeapInit(&hp);int a[] = { 65,100,70,32,50,60 };for (int i = 0; i < 6; i++){HeapPush(&hp, a[i]);}while (!HeapEmpty(&hp)){int top = HeapTop(&hp);printf("%d\n", top);HeapPop(&hp);}HeapDestroy(&hp);return 0;
}

在这里插入图片描述
详情可在土土的博客数据结构——lesson7二叉树堆的介绍与实现中查看🥳🥳

一、堆排序(基础版)

既然是堆排序,那我们首先肯定得有一个堆,这里土土就可以偷个懒将上篇博客中实现的堆代码copy一下🥰🥰

堆的实现

#include"Heap.h"
//堆的初始化
void HeapInit(Heap* hp)
{assert(hp);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}
// 堆的销毁
void HeapDestroy(Heap* hp)
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}
//交换函数
void Swap(HPDataType* a,HPDataType* b)
{HPDataType tmp = *a;*a = *b;*b = tmp;
}//堆向下调整算法
void AdjustDown(HPDataType* a, int n,int parent)
{//找到较小的孩子节点int child = parent * 2 + 1;//向下调整while (child < n){if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}elsebreak;}
}//向上调整
void AdjustUp(HPDataType* a,int child)
{//找到双亲节点int parent = (child - 1) / 2;//向上调整while (child > 0){if (a[parent] > a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}
// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{assert(hp);//判断容量if (hp->size == hp->capacity)//容量满了扩容{int newcapacity = hp->capacity == 0 ? 0 : 2 * hp->capacity;HPDataType* new = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);if (new == NULL){perror("realloc fail");return;}hp->a = new;hp->capacity = newcapacity;}//尾插hp->a[hp->size] = x;hp->size++;//向上调整算法AdjustUp(hp->a,hp->size-1);
}
// 堆的删除,删除堆顶元素
void HeapPop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));Swap(&hp->a[0], &hp->a[hp->size - 1]);hp->size--;//向下调整算法AdjustDown(hp->a, hp->size, 0);}
// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));return hp->a[0];
}
// 堆的数据个数
int HeapSize(Heap* hp)
{assert(hp);return hp->size;}
// 堆的判空
int HeapEmpty(Heap* hp)
{assert(hp);return hp->size == 0;
}

当然在使用这些函数时要记得先声明一下,这里我们都放到一个头文件Heap.h中

Heap.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int HPDataType;
//构建一个结构体封装堆
typedef struct Heap
{HPDataType* a;//数组顺序表int size;//堆元素个数int capacity;//数组空间
}Heap;
//以下是实现堆的函数
// 堆的初始化
void HeapInit(Heap* hp);
// 堆的销毁
void HeapDestroy(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);

使用时只需包含该头文件即可
#include"Heap.h"

堆排序

给定一个数组a[ ] = {7,8,3,5,1,9,5,4},我们需要利用上面的堆来将它进行排序

🤩🤩思路
①我们首先需要将数组中的元素插入堆中(利用HeapPush函数),
💫前面我们已经学习过堆插入函数,它里面利用堆向上调整算法会自动将插入的数据调整为一个堆(我们实现的是小堆);
②然后我们需要获取堆顶元素(也就是小堆中最小的元素),利用HeapTop函数即可;
③获取最小元素后我们就需要获取次小元素,先利用堆的删除函数(HeapPop函数),将堆顶元素(也就是小堆中最小的元素)删除;
💞删除函数中堆向下调整算法又会将剩余元素调整为小堆,此时堆顶元素就是删除一个元素后最小的元素;
④将删除后的元素重新拷贝回数组a中;
⑤循环②③两步直到全部排序成功。

代码实现如下:

#include"Heap.h"
void HeapSort(int* a,int size)
{
Heap hp;
HeapInit(&hp);
//将a中元素插入堆中
for (int i = 0; i < size; i++)
{
HeapPush(&hp, a[i]);
}
//获取堆顶(最小)元素并删除
int i = 0;
while (i < size)
{
a[i++] = HeapTop(&hp);
HeapPop(&hp);
}
HeapDestroy(&hp);
}
int main()
{
int a[] = { 7,8,3,5,1,9,5,4 };
int size = sizeof(a) / sizeof(int);
HeapSort(a,size);
return 0;
}

🥳🥳结果如下:
排序前
在这里插入图片描述
排序后
在这里插入图片描述

💥💥上述堆排序的实现尽管能够实现排序,但是…我们发现如果没有提前实现堆或者准备好堆的代码,我们是没办法实现的,而且我们需要来回拷贝数据,空间复杂度较大。
🥰🥰这里就需要介绍下面简便版堆排序啦~

二、堆排序(简便版)

在土土的数据结构学习笔记数据结构——lesson7二叉树堆的介绍与实现中,详细介绍了堆向上调整算法与堆向下调整算法,接下来我们就可以利用这两个函数来实现堆以及堆的排序🥳🥳

(1)利用堆向上调整算法实现堆

//向上调整算法
void AdjustUp(HPDataType* a,int child)
{//找到双亲节点int parent = (child - 1) / 2;//向上调整while (child > 0){if (a[parent] > a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}

数组a[ ] = {7,8,3,5,1,9,5,4},我们可以看成一个二叉树:
在这里插入图片描述
只需要从第二个数8开始每次读取一个数据都向上调整为堆,那么读完整个数组就可以得到一个堆啦~🥰🥰
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//从第二个数据开始向上调整建堆
for (int i = 1; i < size; i++)
{AdjustUp(a, i);
}

🤩🤩之前基础版排序是又开辟了一个空间来存放a中的数据,排成堆后又每次选取最小的元素拷贝回a中,不仅麻烦而且会增加空间的使用;
所以简便版排序便直接将a看成一个二叉树利用向上调整算法直接成堆,不需要开辟额外的空间。

(2)利用堆向下调整算法排序

那我们应该怎么将堆中的元素排序呢?
🥳🥳这就要利用堆向下调整算法了

思路🥳🥳

①交换首尾元素,将堆中最小的元素(首元素)换到尾部;
②将交换后的尾部元素忽略,剩余元素利用堆向下调整算法(除头外左右子树都是堆)调整为堆;
在这里插入图片描述
③重复②直到全部排完,得到降序数组:
在这里插入图片描述

代码如下:

//排序
int end = size-1;//堆底元素下标
while (end)
{Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;
}

🤩🤩Swap函数在这里:

//交换函数
void Swap(HPDataType* a, HPDataType* b)
{HPDataType tmp = *a;*a = *b;*b = tmp;
}

(3)完整实现🥳🥳

void HeapSort(int* a,int size)
{//从第二个数据开始向上调整建堆for (int i = 1; i < size; i++){AdjustUp(a, i);}//排序int end = size-1;//堆底元素下标while (end){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;}}
int main()
{int a[] = { 7,8,3,5,1,9,5,4 };HeapSort(a, 8);return 0;
}

结果如下:
在这里插入图片描述

✨✨思考:如果我们要排升序应该利用什么堆呢?相信大家通过上面的学习与理解都知道应该用大堆对不对?具体代码大家可以参考上面小堆实现降序来自己试着写一写哦~

三、结语

以上就是堆的应用——堆排序啦~,我们发现可以不用写堆的实现代码就可以将一个数组排成堆🥳🥳,关键在于堆向上调整与向下调整算法的理解与运用,大家都学废了吗 ,💞💞 完结撒花 ~🎉🎉🎉

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#,排列组合的堆生成法(Heap’s Algorithm for generating permutations)算法与源代码

1 排列组合的堆生成法 堆生成算法用于生成n个对象的所有组合。其思想是通过选择一对要交换的元素&#xff0c;在不干扰其他n-2元素的情况下&#xff0c;从先前的组合生成每个组合。 下面是生成n个给定数的所有组合的示例。 示例&#xff1a; 输入&#xff1a;1 2 3 输出&a…

docker安装ES、LogStash、Kibana

文章目录 一、安装Elasticsearch1. 安装Elasticsearch2. 安装IK分词器3. elasticsearch-head 监控的插件4. 配置跨域 二、安装LogStash三、安装kibana四、SpringBoot集成LogStash&#xff0c;将日志输出到ES中五、 启动项目&#xff0c;监控项目运行 提示&#xff1a;以下是本篇…

用这几个工具,写一份简单的产品说明书

产品说明书是任何产品必不可少的一部分。在这个高速运转的消费市场&#xff0c;一份清晰、明了的产品说明书可以让你的产品在同类产品中脱颖而出。然而&#xff0c;制作一份专业级别的产品说明书可能看起来是个挑战。幸运的是&#xff0c;有很多强大的工具可以帮助你轻松制作产…

深入理解Rem适配:移动端网页设计的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Flutter学习9 - http 中 get/post 请求示例

1、配置 http pubspec.yaml dependencies:http: ^0.13.4flutter:sdk: flutterhttp 库最新插件版本查看&#xff1a;https://pub.dev/packages/http不一定要用最新版本 http&#xff0c;要使用项目所能支持的版本 .dart import package:http/http.dart as http;2、示例 &a…

【粉丝福利第四期】:《低代码平台开发实践:基于React》(文末送书)

文章目录 前言一、React与低代码平台的结合优势二、基于React的低代码平台开发挑战三、基于React的低代码平台开发实践四、未来展望《低代码平台开发实践&#xff1a;基于React》五、粉丝福利 前言 随着数字化转型的深入&#xff0c;企业对应用开发的效率和灵活性要求越来越高…

【C++】手撕string类(超实用!)

前言 一、标准库中的string类 1.1 string类介绍 1.2 string的常用接口 1.2.1 常用的构造函数 1.2.2 容量操作接口 &#xff08;1&#xff09;size &#xff08;2&#xff09;capacity &#xff08;3&#xff09;empty &#xff08;4&#xff09;clear &#xff08…

gRPC-第二代rpc服务

在如今云原生技术的大环境下&#xff0c;rpc服务作为最重要的互联网技术&#xff0c;蓬勃发展&#xff0c;诞生了许多知名基于rpc协议的框架&#xff0c;其中就有本文的主角gRPC技术。 一款高性能、开源的通用rpc框架 作者作为一名在JD实习的Cpper&#xff0c;经过一段时间的学…

(vue)适合后台管理系统开发的前端框架

(vue)适合后台管理系统开发的前端框架 1、D2admin 开源地址&#xff1a;https://github.com/d2-projects/d2-admin 文档地址&#xff1a;https://d2.pub/zh/doc/d2-admin/ 效果预览&#xff1a;https://d2.pub/d2-admin/preview/#/index 开源协议&#xff1a;MIT 2、vue-el…

计算机网络——概述

计算机网络——概述 计算机网络的定义互连网&#xff08;internet&#xff09;互联网&#xff08;Internet&#xff09;互联网基础结构发展的三个阶段第一个阶段——APPANET第二阶段——商业化和三级架构第三阶段——全球范围多层次的ISP结构 ISP的作用终端互联网的组成边缘部分…

嵌入式学习36-TCP要点及http协议

TCP发送文件的粘包问题 1. 例&#xff1a; 发端 1.flv-------->收端 1.flv csfga 2.解决 1. sleep&#xff08;1&#xff09; 延时发送 2.自…

服务器又被挖矿记录

写在前面 23年11月的时候我写过一篇记录服务器被挖矿的情况&#xff0c;点我查看。当时是在桌面看到了bash进程CPU占用异常发现了服务器被挖矿。 而过了几个月没想到又被攻击&#xff0c;这次比上次攻击手段要更高明点&#xff0c;在这记录下吧。 发现过程 服务器用的是4090…

【文档智能】再谈基于Transformer架构的文档智能理解方法论和相关数据集

前言 文档的智能解析与理解成为为知识管理的关键环节。特别是在处理扫描文档时&#xff0c;如何有效地理解和提取表单信息&#xff0c;成为了一个具有挑战性的问题。扫描文档的复杂性&#xff0c;包括其结构的多样性、非文本元素的融合以及手写与印刷内容的混合&#xff0c;都…

ai语音克隆:用AI大模型开发点亮你的创作天地!

在当今快速发展的科技时代&#xff0c;人工智能技术已经深入到我们生活的方方面面。AI语音克隆作为其中的一种应用&#xff0c;正在逐渐走进人们的视野&#xff0c;为人们的创作提供了全新的可能性。 人类创作的过程往往是一个灵感迸发、思绪飞扬的过程。但有时候&#xff0c;…

实现QT中qDebug()的日志重定向

背景&#xff1a; 在项目开发过程中&#xff0c;为了方便分析和排查问题&#xff0c;我们需要将原本输出到控制台的调试信息写入日志文件&#xff0c;进行持久化存储&#xff0c;还可以实现日志分级等。 日志输出格式&#xff1a; 我们需要的格式包括以下内容&#xff1a; 1.…

eclipse搭建java web项目

准备条件 eclipsejdk1.8 &#xff08;配置jdk环境&#xff09;apache-tomcat-8.5.97&#xff08;记住安装位置&#xff09; 一 点击完成 开始创建javaweb项目 import java.io.IOException; import java.io.PrintWriter;import javax.servlet.ServletException; import javax.s…

Neo4j安装 Linux:CentOS、openEuler 适配langchain应用RAG+知识图谱开发 适配昇腾910B

目录 Neo4j下载上传至服务器后进行解压运行安装JAVA再次运行在windows端打开网页导入数据 Neo4j下载 进入Neo4j官网下载页面 向下滑动找到 Graph Database Self-Managed 选择 社区版&#xff08;COMMUNITY&#xff09; 选择 Linux / Mac Executable Neo4j 5.17.0 (tar) 单机下…

Android Studio编译及调试知识

文章目录 Android Studio编译kotlin项目Android Studio编译Java和kotlin混合项目的过程gradle打印详细错误信息&#xff0c;类似这种工具的使用Android apk 从你的代码到APK打包的过程&#xff0c;APK安装到你的Android手机上的过程&#xff0c;最后安装好的形态&#xff0c;以…

【Kotlin】类和对象

1 前言 Kotlin 是面向对象编程语言&#xff0c;与 Java 语言类似&#xff0c;都有类、对象、属性、构造函数、成员函数&#xff0c;都有封装、继承、多态三大特性&#xff0c;不同点如下。 Java 有静态&#xff08;static&#xff09;代码块&#xff0c;Kotlin 没有&#xff1…

Python算法题集_搜索二维矩阵

Python算法题集_搜索二维矩阵 题74&#xff1a;搜索二维矩阵1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【矩阵展开为列表二分法】2) 改进版一【行*列区间二分法】3) 改进版二【第三方模块】 4. 最优算法5. 相关资源 本文为Python算法题集之…