排序——堆排序

本节继续复习排序算法。这次复习排序算法中的堆排序。 堆排序属于选择排序。

目录

什么是堆?

堆排序

堆排序的思想

堆排代码

向下调整算法

 堆排整体


什么是堆?

在复习堆排序之前, 首先我们需要回顾一下什么是堆 。

堆的本质其实是一个数组。 它的物理结构本质上是一个数组。 但是它的逻辑结构是一棵完全二叉树。我们在判断一个数组是否是一个堆的时候根据的就是它的逻辑结构。

那么怎么根据它的逻辑结构判断是否是一个堆。 

首先堆的逻辑结构的二叉树的每一个孩子节点都大于它的每一个父亲, 就是堆。 这种堆叫做小堆。 如果它的逻辑结构的每一个孩子节点都小于它的父亲节点。 它同样是个堆, 同时这种堆叫做大堆。 

如图数组就是一个小堆

将该小堆的逻辑结构画出来就是这样的:

我们可以看到,在这棵二叉树之中的每一个父亲节点都小于它的孩子节点。 那么他就是一个小堆。 

大堆就是它的每个父亲节点都大于它的每个孩子节点

如图:

堆排序

堆排序的思想

堆排序的思想利用了大堆或小堆的结构。

我们从上面的解析可以发现。 大堆中, 第一个元素一定是整个数组中最大的那个元素;小堆中,第一个元素一定是数组中最小的那个元素。

堆排的核心就是每一趟都将堆的第一个元素和堆的最后一个元素交换位置。 然后让这个堆的元素个数减一。 同时通过向下调整算法重新建堆。 循环往复。 不断选出最大或者最小的那个数据放到堆的最后。

不知道向下调整算法可以去回顾本节:堆——c语言实现堆结构-CSDN博客

现在我们来分析一下堆的排序过程。 

我们使用小堆进行堆排:

 

第一步,将第一个元素也就是堆顶的元素和最后一个元素交换:

然后堆的大小减一:

向下调整算法重新建堆: 

 堆的第一个元素再次和堆最后一个元素交换位置:

 堆的大小减一:

 然后向下调整算法重新建堆:

然后堆的第一个元素再和堆的最后一个元素交换位置, 然后堆的大小减一, 然后向下调整算法调堆。 循环,一直到堆只剩下一个元素位置。 排好后就是这样的:​​​​​​​ 现在已经有序,同时是降序。 这时我们使用的是小堆排的。其实这里就是用大小堆控制升序降序。 小堆排的就是降序, 大堆排的就是升序。 

堆排代码

向下调整算法

我们先再来实现一次向下调整算法:


//向下调整建大堆。
void AdjustDownSort(int* a, int sz, int parent)
{}

a是要建堆的数组, sz是数组的大小。 parent是建堆的堆顶节点 

 


//向下调整建大堆。
void AdjustDownSort(int* a, int sz, int parent)
{int child = parent * 2 + 1;//先假设左孩子小。 }

 我们先假设左孩子比较大(注意, 我这里要建的是大堆)。


//向下调整建大堆。
void AdjustDownSort(int* a, int sz, int parent)
{int child = parent * 2 + 1;//先假设左孩子小。 while (child < sz) //控制条件是孩子不能超出整个数据。 {child = 2 * parent + 1;}
}

然后使用child指针控制循环结束。 当child指针超出整个数组的时候就不用再向下调整了。 

 


//向下调整建大堆。
void AdjustDownSort(int* a, int sz, int parent)
{int child = parent * 2 + 1;//先假设左孩子小。 while (child < sz) //控制条件是孩子不能超出整个数据。 {if (child + 1 < sz && a[child] < a[child + 1])//让child指向大的那个孩子。说明建大堆, 排升序。 {child++;}child = 2 * parent + 1;}
}

 因为我们是假设的左孩子比较大, 所以进入循环之后我们要比较一下左右孩子。如果右孩子更大的话就假设错误, child指针需要加加。

 


//向下调整建大堆。
void AdjustDownSort(int* a, int sz, int parent)
{int child = parent * 2 + 1;//先假设左孩子小。 while (child < sz) //控制条件是孩子不能超出整个数据。 {if (child + 1 < sz && a[child] < a[child + 1])//让child指向大的那个孩子。说明建大堆, 排升序。 {child++;}//if (a[child] > a[parent]) {Swap(&a[child], &a[parent]);parent = child;//继续向下调整。 父亲便孩子, 孩子变成孩子的孩子。child = 2 * parent + 1;}else {break;//如果父亲比小的孩子还要大, 那么这个父亲就是一个堆。 就不需要再调整建堆了。}//}
}

 然后在每次循环中都比较一下父亲节点和两个孩子中更小的节点。 如果孩子比父亲还要大。 就交换孩子节点和父亲节点。

如果孩子节点比父亲节点要小。 那么就说明这个堆已经建好了。 就跳出循环。

 堆排整体

一、


//堆排序
void HeapSort(int* a, int sz) 
{}

 首先, 堆排的函数名以及传参。 除了快排传参基本都是传要排序的数组和数组的大小。

二、


//堆排序
void HeapSort(int* a, int sz) 
{int end = sz - 1;//先建堆, 向下调整建大堆for (int i = (end - 1) / 2; i >= 0; i--)//从最后一个节点的父亲开始向下调整。  一棵子树一棵子树的建成堆。最后整体成堆{AdjustDownSort(a, sz, i);//向下调整算法建大堆。}//while (end > 0) {Swap(&a[0], &a[end]);//让第n个数据和堆顶最大的那个数据交换, 就能让第end个数据是最大的那个数据。 AdjustDownSort(a, end, 0);//第n个数据和堆顶数据交换后,前end - 1个数据只有堆顶不符合堆, 堆顶左右子树都是堆, 这时满足//向下调整算法。 然后向下调整。 end--;}}

堆排的实现过程就是我们上面分析的过程。 首先需要一个堆。 所以先建堆。 

建完堆之后就交换堆顶和最后一个数据。 然后堆的大小减一调堆。循环往复。  

 

 

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

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

相关文章

11.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-接管游戏接收网络数据包的操作

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;接管游戏发送数据的操作 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;8256eb53e8c16281bc1a29cb8d26d352bb5bbf4c 代…

负载均衡.

简介: 将请求/数据【均匀】分摊到多个操作单元上执行&#xff0c;负载均衡的关键在于【均匀】。 负载均衡的分类: 网络通信分类 四层负载均衡:基于 IP 地址和端口进行请求的转发。七层负载均衡:根据访问用户的 HTTP 请求头、URL 信息将请求转发到特定的主机。 载体维度分类 硬…

绕过付费,畅享网络:自由浏览付费内容 | 开源日报 No.185

iamadamdev/bypass-paywalls-chrome Stars: 38.8k License: NOASSERTION bypass-paywalls-chrome 是一个用于 Chrome 和 Firefox 的网页浏览器扩展&#xff0c;可帮助绕过特定网站的付费墙。 可以绕过多个指定网站的付费墙支持自动更新&#xff08;仅限 Firefox 版本&#x…

从头构建gpt2 基于Transformer

从头构建gpt2 基于Transformer VX关注{晓理紫|小李子}&#xff0c;获取技术推送信息&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持&#xff01;&#xff01; 如果你感觉对你有所帮助&#xff0c;请关注我。 源码获取 VX关注晓理紫并回复“chatgpt…

消息中间件之RocketMQ源码分析(二十九)

延迟消息投递机制 RocketMQ在存储延迟消息时&#xff0c;将其保存在一个系统的Topic中&#xff0c;在创建ConsumeQueue时&#xff0c;tagCode字段中保存着延迟消息需要被投递的时间&#xff0c;通过这个存储实现的思路&#xff0c;我们可以总结出延迟消息的投递过程:通过定时服…

C++入门07 数组、指针与字符串

图源&#xff1a;文心一言 听课笔记简单整理&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 第1版&#xff1a;听课的记录代码~&#x1f9e9;&#x1f9e9; 编辑&#xff1a;梅头脑&#x1f338; 审核&#xff1a;文心一言 目录 &#x1f433;课程来源 &#x1…

逆序遍历字符串(不改变内存地址)

题目&#xff1a;逆序遍历字符串"ABCDEFG" 实现思路&#xff1a; 使用StringBuilder创建对象&#xff0c;因为String字符串是不可变的&#xff0c;而StringBuilder内部的方法没有被final关键字修饰&#xff0c;所以将s1的字符串内容传给StringBuilder创建的对象ret…

模拟算法题练习(一)(扫雷,灌溉,回文日期)

目录 模拟算法介绍&#xff1a; &#xff08;一、扫雷&#xff09; &#xff08;二、灌溉&#xff09; &#xff08;三、回文日期&#xff09; 有一说一这题大佬的题解是真的强 模拟算法介绍&#xff1a; 模拟算法通过模拟实际情况来解决问题&#xff0c;一般容易理解但是实…

c语言游戏实战(10):坤坤的篮球回避秀

前言&#xff1a; 这款简易版的球球大作战是博主耗时两天半完成的&#xff0c;玩家需要控制坤坤在游戏界面上移动&#xff0c;来躲避游戏界面上方不断掉下来的篮球。本游戏使用C语言和easyx图形库编写&#xff0c;旨在帮助初学者了解游戏开发的基本概念和技巧。 在开始编写代…

SpringMVC01、回顾MVC

1、回顾MVC 1.1、什么是MVC MVC是模型(Model)、视图(View)、控制器(Controller)的简写&#xff0c;是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式&#xff0c;MVC是一种架构模式。…

Node.js中的并发和多线程处理

在Node.js中&#xff0c;处理并发和多线程是一个非常重要的话题。由于Node.js是单线程的&#xff0c;这意味着它在任何给定时间内只能执行一个任务。然而&#xff0c;Node.js的事件驱动和非阻塞I/O模型使得处理并发和多线程变得更加高效和简单。在本文中&#xff0c;我们将探讨…

恋爱话术小程序源码支持多种流量主模式

源码介绍 这就是一款恋爱话术小程序,该款小程序相对来说还是挺强大的 这款小程序基本分段都是和外面几千块几百块的分段是一样的,基本就是从开场-情绪-聊天-升级-邀约-约会等几大分类开始 然后每一大分类下面都有N个小分类来做识别 另外也支持输入对方的话或关键词获取相关的话…

Container killed on request. Exit code is 143

Bug信息 WARN YarnAllocator: Container marked as failed: container_e33_1480922439133_0845_02_000002 on host: hdp4. Exit status: 143. Diagnostics: Container killed on request. Exit code is 143 Container exited with a non-zero exit code 143 Killed by externa…

大数据技术(一)

大数据技术概述 大数据技术层面及其功能 数据采集与预处理 利用ETL(extract-transform-load)工具将分布的、异构数据源中的数据&#xff0c;如关系数据、平面数据文件等&#xff0c;抽取到临时中间层后进行清洗、转换、集成&#xff0c;最后加载到数据仓库或数据集市中&…

机器人 标准DH与改进DH

文章目录 1 建立机器人坐标系1.1 连杆编号1.2 关节编号1.3 坐标系方向2 标准DH(STD)2.1 确定X轴方向2.2 建模步骤2.3 变换顺序2.4 变换矩阵3 改进DH(MDH)3.1 确定X轴方向3.2 建模步骤3.3 变换顺序3.4 变换矩阵4 标准DH与改进DH区别5 Matlab示例参考链接1 建立机器人坐标系 1.1…

【Python】变量的引用

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

微服务day04-基于Feign的远程调用

一.Feign的认识 是http客户端&#xff0c;因为使用RestTemplate存在一些问题&#xff1a;代码可读性差&#xff0c;参数配置费事&#xff0c;不够优雅… String url"http://userservice/user/"order.getUserId(); User userrestTemplate.getForObject(url,User.cla…

【AIGC】如何提高Prompt准确度

前言 随着人工智能的迅猛进展&#xff0c;AIGC&#xff08;通用人工智能聊天工具&#xff09;已成为多个行业中不可或缺的自然语言处理技术。Prompt作为AIGC系统的一项关键功能&#xff0c;在工具的有效运作中发挥了举足轻重的作用。本篇文章将深入探讨Prompt与AIGC之间的紧密…

OpenLayers线性渐变和中心渐变(径向渐变)

目录 1.前言2.添加一个面要素3.线性渐变3.1 第一个注意点3.2 第二个注意点 4.中心渐变&#xff08;径向渐变&#xff09;5.总结 1.前言 OpenLayers官网有整个图层的渐变示例&#xff0c;但是没有单个要素的渐变示例&#xff0c;我们这里来补充一下。OpenLayers中的渐变是通过fi…

PostgreSQL restartpoint 原理详解

背景 大部分人对 PG 的 checkpoint 机制会熟悉一点&#xff0c;但是对 restartpoint 却不太熟悉&#xff0c;网上介绍这方面的文章也比较少。因此&#xff0c;本文将以 PG 14.7 的社区代码为基础&#xff0c;介绍 PG 中的 restartpoint 机制。 原理介绍 什么是 restartpoint…