图解堆排序【一眼看穿逻辑思路】

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。
P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。

  

目录

  • 1、堆的概念
  • 2、实现堆排序前的准备工作
  • 3、堆排序的思路
    • 3.1 第一步
    • 3.2 第二步
  • 4、结语

1、堆的概念


  在了解堆排序之前我们先要了解什么是堆:一个按照完全二叉树的储存方式存储的一维数组我们称之为堆。


在这里插入图片描述


  而堆又可以分为大堆和小堆。
  大堆:二叉树中的父结点在数值上都比子结点大。
  小堆:二叉树中的父结点在数值上都比子结点小。
  下图在就是一组较为明显的大小堆。

在这里插入图片描述

  故堆排序就是在堆的前提下进行排序。




2、实现堆排序前的准备工作


  我们需要完成的准备工作是实现一个关于二叉树即堆的向下调整函数,此处我们写为HeapAdjustDown。
void Swap(int* p1,int* p2) //简单的交换函数
{
	int* tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}


void HeapAdjustDown(int* a,int n,int parent)
									//a代表数组的地址,n为数组元素个数,parent为当前元素所在下标。
{
	int child = parent * 2 + 1;		//假设左孩子大于或小于右孩子.
	while(child < n)				//结束条件为到达最后一层时,最后一层没有子。
	{
		if(child + 1 < n && a[child + 1] > a[child])//判断左孩子是否真的大于或小于右孩子,如果不是
		{											//让child代表右边孩子的下标。
			++child;
		}
		if(a[child] > a[parent])	//判断父与子的关系,如果父大于或小于子,让其交换位置。
		{
			Swap(&a[child],&a[parent])
			parent = child;			//此处令交换的子的下标成为新的parent下标,即沿着交换路径一致进行
									//比较,直至到达最后一层。
			child = parent * 2 + 1;
		}
		else
		{
			break;					//当不满足大小条件是就会进来,即已经按照需求将堆排列成了大堆或者小堆。
		}
	}
}

  上面就是我们所完成的准备工作,其中
if(child + 1 < n && a[child + 1] < a[child])
if(a[child] < a[parent])

  这两条判断语句中的数组内成员比较可以更换比较符号。
  当使用 “ < ” 号时,第一条判断依据所筛选的时两个子中较小的一个。
           第二条判断语句就是比较所选的子是否小于父,如果小于就进行交换。
           这样进行调整后的堆就称之为小堆,即父皆比子小。
  当使用 “ > ” 号时,第一条判断依据所筛选的时两个子中较大的一个。
           第二条判断语句就是比较所选的子是否大于父,如果大于就进行交换。
           这样进行调整后的堆就称之为大堆,即父皆比子大。




3、堆排序的思路


3.1 第一步


  我们首先要做的就是将得到的数组进行调整,将其调整为大堆或者小堆。
  故写一个函数来进行操作较为方便:HeapSort
void HeapSort(int* a,int n)//此处的n为数组的元素个数
{
	for(int i = (n - 1 - 1) / 2; i >= 0; i--)//此处为何从(n - 1 - 1) / 2开始,后面会有图解,耐心一点哦~
	{
		//然后调用我们的向下调整函数。
		HeapAdjustDown(a,n,i);
	}
}

  到这里后,我们就完成了对数组的大堆或者小堆化,此处我们所进行的是大堆化处理。
  下面就进行我们此截止到目前的看图说话:
  假设我们所拥有的数组是{1,3,5,7,9,2,4,6,8,10}。
在这里插入图片描述  其在数组中和在堆中的存放方式如上图所示,我们按照上述代码执行。
在这里插入图片描述
  而后我们在数组元素9的基础上进行向下调整。
在这里插入图片描述
  这一步进行完后,我们的i–,此时的i = 3,也就是我们的元素7所在下标,故此时在数组元素7的基础上向下调整。
在这里插入图片描述
  故循环的意义就是从最后一层的父开始进行向下调整,一致循环到根位置,后面我们直接展示过程图,不在进行比较讲解。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  到此处我们的大堆构建也算完成了。
在这里插入图片描述
  根据VS验证我们所进行的数组大堆化也是正确无误的。
  此处又会有看官提出问题,我们为什么不从数组的头部开始进行向下调整呢,反而从尾部开始呢?
在这里插入图片描述
  我们直接上图,当我们从头部开始时,进行向下调整,得到的却不是大堆。这是因为:
在这里插入图片描述
  而后我们也同样直接展示过程图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  至此我们所得到的新数组也就和上述实验数组结果一致,为{5,9,4,8,10,2,1,6,7,3}。
  总而言之,我们不从头部开始进行向下调整,是因为以这样的方式进行时,每一次调整只会调整当前位置及当前位置向后的数据,而不会向前进行比较,会造成不可避免地bug。


3.2 第二步


  我们将数组大堆或小堆化后,就可以进行排序了,此时我们进行的是升序排列,排序的代码如下:
void HeapSort(int* a,int n)//此处的n为数组的元素个数
{
	for(int i = (n - 1 - 1) / 2; i >= 0; i--)//此处为何从(n - 1 - 1) / 2开始,后面会有图解,耐心一点哦~
	{
		//然后调用我们的向下调整函数。
		HeapAdjustDown(a,n,i);
	}
	int end = n - 1;		//原理下文解释
	while(end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

  我们可以看到代码中创建了一个变量 “ end ”,其代表的含义为最后一个元素的数组下标,我们在前文中已经将数组进行了大堆化,故我们数组的第一个元素是大于其他元素的。
在这里插入图片描述
  此时我们将第一个数和最后一个数据交换位置,这样最大的数就处在了末尾,然后按照同样的方式对前面九个数字进行大堆化,这样就又会有一个第二大的数字排列在第一位,然后进行下一次循环,然后我们将 end–,进入下一次循环。下面我们展示过程图,并不在对途中内容进行讲解:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  依次向下进行最终就得到了如下的数组。
在这里插入图片描述

在这里插入图片描述
  通过验证我们可以得到上述方法是可行且正确无误的。
  从中我们也可以发现一个规律,我们通过创建大堆可以得到升序的序列,通过类比,我们明白也可以通过创建小堆可以得到降序的序列。




4、结语


  十分感谢您观看我的原创文章。
  本文主要用于个人学习和知识分享,学习路漫漫,如有错误,感谢指正。
  如需引用,注明地址。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Cannot read properties of undefined (reading ‘init‘)报错

出现这个报错是印象项目没有引echarts包 npm i echarts 下包 然后在main.js中引入 import echarts from echarts Vue.prototype.$echarts echarts 如果还不行 import * as echarts from echarts; 更改一下引入方式 ok了

OpenHarmony 实战开发——使用分布式菜单创建点餐神器

随着社会的进步与发展&#xff0c;科技手段的推陈出新&#xff0c;餐饮行业也在寻求新的突破与变革&#xff0c;手机扫描二维码点餐系统已经成为餐饮行业的未来趋势&#xff0c;发展空间巨大&#xff1b;扫码点餐&#xff0c;是“互联网餐饮”潮流的产物&#xff0c;可以有效地…

Leetcode—2244. 完成所有任务需要的最少轮数【中等】

2024每日刷题&#xff08;136&#xff09; Leetcode—2244. 完成所有任务需要的最少轮数 实现代码 class Solution { public:int minimumRounds(vector<int>& tasks) {unordered_map<int, int> map;for(int task: tasks) {map[task];}int ans 0;// freq 1 …

嵌入式学习-输入捕获

简介 框图介绍 输入通道部分 比较捕获寄存器与事件生成 相关寄存器

【论文阅读 | 三维重建】3D Gaussian Splatting for Real-Time Radiance Field Rendering(3DGS)

Abstract 辐射场方法最近彻底改变了用多张照片或视频捕获的新颖视图合成&#xff0c;然而实现高视觉质量仍然需要训练和渲染成本高昂的神经网络&#xff0c;而最近更快的方法不可避免地要牺牲速度来换取质量。对于无边界和完整的场景和1080P分辨率的渲染&#xff0c;目前没有任…

低成本、功能强大!德思特提供一体化WiFi 6E信道测试方案!

​ 作者介绍 一、方案介绍 伴随WiFi 6E与WiFi 7的提出&#xff0c;WIFI划分出一个全新的5.925GHz-7.125GHz 之间的80MHz和160MHz频段。1200MHz的带宽是迄今为止最宽的&#xff0c;是之前2.4GHz和5GHz WiFi 频段可用带宽的数倍。此外WiFi 6E引入了以下技术&#xff1a; ● 多…

全网最全的Postman接口自动化测试!

该篇文章针对已经掌握 Postman 基本用法的读者&#xff0c;即对接口相关概念有一定了解、已经会使用 Postman 进行模拟请求的操作。 当前环境&#xff1a; Window 7 - 64 Postman 版本&#xff08;免费版&#xff09;&#xff1a;Chrome App v5.5.3 不同版本页面 UI 和部分…

搞大事!法国邀请芬兰公司建量子工厂

法国当地时间5月13日&#xff0c;法国总统马克龙宣布启动2024年度“选择法国”&#xff08;Choose France&#xff09;商业峰会。今年峰会召开前&#xff0c;法国赢得了创纪录的150亿欧元外国投资承诺&#xff0c;覆盖从人工智能到制药和能源等领域。 而涉及到量子领域最重磅的…

✅HTTPS和HTTP的区别是什么?

一、问题解析 HTTP和HTTPS是两种协议&#xff0c;分别是Hypertext Transfer Protocol和HyperText Transfer Protocol Secure。 HTTPS还经常被称之为HTTP over SSL或者HTTP over TSL&#xff0c;HTTPS经由HTTP进行通信&#xff0c;但利用SSL/TLS来加密数据包。 他们的区别主要…

打个样为centos安装mysql(下载安装)

文章目录 一、下载二、卸载mariadb三、创建用户和组四、解压并安装mysql五、修改my.cnf六、配置环境七、初始化数据库八、启动mysql服务、改密码配置远程链接九、完成 一、下载 https://downloads.mysql.com/archives/community/ 二、卸载mariadb 安装mysql的话会和mariadb的…

python:SunMoonTimeCalculator

# encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 许可信息查看&#xff1a; # 描述&#xff1a; https://github.com/Broham/suncalcPy # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # Datetime : 2024/5/14 21:59 # User …

通过 AWS Glue 同步 MaxCompute 数据到 S3

1. 下载驱动 下载 3.3.6 版本的 driver wget https://github.com/aliyun/aliyun-odps-jdbc/releases/download/v3.3.6/odps-jdbc-3.3.6-jar-with-dependencies.jar将下载的jar包上传到 S3 指定目录下。(版本会影响方案的成功&#xff0c;4.x 以上版本验证是不可行的) 2. 在 …

二手手机行业商家如何利用二手机店erp进行破局?

在数字化和AI发展越发先进的的今天&#xff0c;二手手机市场正迎来前所未有的变革。途渡科技精心打造的超机购ERP管理软件&#xff0c;凭借其独特的智能化、高效化特点&#xff0c;正在引领这场变革&#xff0c;为二手手机商家提供全面、深度的数字化管理解决方案。二手手机商家…

谷歌广告账号被暂停是因为什么?防封点大全背好!

跨境出海业务少不了需要做Google Ads推广业务&#xff1b;其中让投手们闻风丧胆的消息就是帐户被暂停。当 Google 检测到任何违反其政策且可能损害用户在线体验的行为时&#xff0c;就会发生这种情况。那么如何在做广告推广的同时&#xff0c;保证账号不被封禁呢&#xff1f;看…

如何管理测试用例?测试用例有什么管理工具?YesDev

3.1 测试用例 测试用例(Test Case) 是指对一项特定的软件产品进行测试任务的描述&#xff0c;体现测试方案、方法、技术和策略。其内容包括测试目标、测试环境、输入数据、测试步骤、预期结果等。简单地认为&#xff0c;测试用例是为某个特殊目标而编制的一组测试输入、执行条…

Postman基础功能-前置脚本与接口关联

大家好&#xff0c;今天给大家分享一下关于 Postman 工具中的前置脚本与接口关联的使用&#xff0c;本文中汇大量用到关于变量的知识&#xff0c;前段时间给大家除了一篇文章分享&#xff0c;可以参考&#xff1a; Postman基础功能-变量设置与使用 一、前置脚本 介绍&#xf…

AI 写 SQL 真的靠谱吗?腾讯游戏在 AI+ 湖仓一体的实践

作者&#xff1a;腾讯游戏数据技术负责人 刘岩 导读 腾讯游戏是全球领先的游戏开发和运营商&#xff0c;其数据团队拥有十余年、700 款大型游戏的数据工作沉淀。复杂的业务环境下&#xff0c;腾讯游戏数据团队每年需要处理超过 3 万个数据提取需求&#xff0c;SQL 编写需要耗费…

.NET 4.8和.NET 8.0的区别和联系、以及查看本地计算机的.NET版本

文章目录 .NET 4.8和.NET 8.0的区别查看本地计算机的.NET版本 .NET 4.8和.NET 8.0的区别 .NET 8.0 和 .NET 4.8 之间的区别主要体现在它们的发展背景、目标平台、架构设计和功能特性上。下面是它们之间的一些主要区别&#xff1a; 发展背景&#xff1a; .NET 4.8 是.NET Fram…

单位内部防泄密策略与技术实践

在信息时代&#xff0c;企业内部数据安全至关重要&#xff0c;尤其是涉及核心竞争力的重要文件&#xff0c;员工的不当操作或恶意泄露都可能给企业带来重大损失。本文将从制度建设、技术防护、以及日常管理三个方面入手&#xff0c;探讨如何构建一套行之有效的内部防泄密体系&a…

20232803 2023-2024-2 《网络攻防实践》实践九报告

目录 1.实践内容2.实践过程2.1 手工修改可执行文件&#xff0c;改变程序执行流程&#xff0c;直接跳转到getShell函数2.2 利用foo函数的Bof漏洞&#xff0c;构造一个攻击输入字符串&#xff0c;覆盖返回地址&#xff0c;触发getShell函数2.3 注入一个自己制作的shellcode并运行…