堆排序的实现原理

一、什么是堆排序?

        堆排序就是将待排序元素以一种特定树的结构组合在一起,这种结构被称为堆。

        堆又分为大根堆和小根堆,所谓大根堆即为所有的父节点均大于子节点,但兄弟节点之间却没有什么严格的限制,小根堆恰恰相反,是所有的根节点均小于子节点。

        所以为了能够实现堆排序,第一个步骤就是将待排序的元素建成堆的形式,其次就是将建好的大根堆(小根堆)与堆的最后一个元素交换,然后再对新的堆进行向下的调整,但是在调整过程中,所有经过交换过的堆底元素不再进行新的调整,直到将倒数第二个元素调整完毕后结束。

        所以说堆排序虽说效率较高,但是它的算法步骤却不如其他排序那么明了,需要将它的每一个算法步骤了解清楚后,才能清晰的解析出来。

二、堆排序的算法步骤

        在排序家族中,堆排序是一种效率比较高的方法,它的 时间复杂度为O(nlogn),空间复杂度为O(1),它的主要排序步骤为:建堆、交换堆顶、堆底元素再向下调整。

        但是在此之前,我们需要先解析出两个分支算法,分别是向下调整和向上调整。

        顾名思义,向上(下)调整分别是从堆底(顶)为起始向堆顶(底)进行调整,目的则是严格维护堆的结构不被破坏。

        在本文的演示中,我们暂且以大根堆为例。

2.1向下调整

        首先,我们以【2,6,3,0,7】为例进行演示。

        我们先按照顺序构建堆,如下所示:

        然后我们建立两个int类型的变量parent和child,分别指向2和它的子节点,这里子节点的公式为(parent*2+1)。

        接下来就是要将parent所指的元素和child所指的元素进行比较,如果parent所指元素小于child所指元素则进行交换,再更新两个变量的位置,如果child所指元素不大于parent所指元素,则跳出循环。

                这样,一趟的向下调整就完成了,下面我们用代码实现:

//向下调整
void Modify_down(int parent , int end)
{int child = parent * 2 + 1;while (child <= end){if (child + 1 < end && _v[child] < _v[child + 1]){child++;}if (_v[child] > _v[parent]){swap(_v[parent], _v[child]);parent = child;child = child * 2 + 1;}elsebreak;}
}

2.2向上调整

        向上调整和向下调整有所不同,需要先找出其孩子节点中最大的那个,比较之后再进行交换操作,以【2,6,7,0,3】为例。

        调整过程中,计算父节点的计算方法为【(child-1)/2】,然后比较兄弟节点,找出最大的那个,如果孩子节点大于父节点,就进行交换,然后更换parent和child的下标位置,如果子节点小于父节点就跳出循环。代码如下:

//向上调整
void Modify_up(int child)
{int parent = (child - 1) / 2;while (child > 0){if (_v[child] > _v[parent]){swap(_v[parent], _v[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}

2.3堆排序

        完成两个核心的算法后,我们最后只需将堆排序归纳一下即可。

1、建堆,将堆调整至合法。

//向上调整
void Modify_up(int child)
{int parent = (child - 1) / 2;while (child > 0){if (_v[child] > _v[parent]){swap(_v[parent], _v[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}
//建堆
for (int i = 1; i < _v.size(); i++)
{Modify_up(i);
}

2、交换堆顶和堆底元素,然后再进行向下调整堆,在这里对于堆底的下标我们以变量“end”来控制,当end<=0时,则跳出循环。

//向下调整
void Modify_down(int parent , int end)
{int child = parent * 2 + 1;while (child <= end){if (child + 1 < end && _v[child] < _v[child + 1]){child++;}if (_v[child] > _v[parent]){swap(_v[parent], _v[child]);parent = child;child = child * 2 + 1;}elsebreak;}
}int end = _v.size() - 1;
while (end > 0)
{swap(_v[0], _v[end]);end--;Modify_down(0, end);
}

三、堆排序完整代码

class heapsort
{
public:heapsort(vector<int>& v):_v(v){}void heap_sort(){for (int i = 1; i < _v.size(); i++){Modify_up(i);}int end = _v.size() - 1;while (end > 0){swap(_v[0], _v[end]);end--;Modify_down(0, end);}}void Print(){for (int i = 0; i < _v.size(); i++){cout << _v[i] << " ";}}
protected://向上调整void Modify_up(int child){int parent = (child - 1) / 2;while (child > 0){if (_v[child] > _v[parent]){swap(_v[parent], _v[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}}//向下调整void Modify_down(int parent , int end){int child = parent * 2 + 1;while (child <= end){if (child + 1 < end && _v[child] < _v[child + 1]){child++;}if (_v[child] > _v[parent]){swap(_v[parent], _v[child]);parent = child;child = child * 2 + 1;}elsebreak;}}
private:vector<int> _v;
};

四、、堆排序的适用场景

        堆排序适用于关键字较多的情况,如:在几亿个关键字中找出前十个最大的数据,我们只需建立小根堆,然后依次循环十次就能得到想要的数据了。

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

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

相关文章

高通安卓12-在源码中查找应用的方法

1.通过搜索命令查找app 一般情况下&#xff0c;UI上看到的APP名称会在xml文件里面定义出来&#xff0c;如 搜索名字为WiGig的一个APP 执行命令 sgrep "WiGig" 2>&1|tee 1.log 将所有的搜索到的内容打印到log里面 Log里面会有一段内容 在它的前面是这段内…

Stable Diffusion部署教程,开启你的AI绘图之路

本文环境 系统&#xff1a;Ubuntu 20.04 64位 内存&#xff1a;32G 环境安装 2.1 安装GPU驱动 在英伟达官网根据显卡型号、操作系统、CUDA等查询驱动版本。官网查询链接https://www.nvidia.com/Download/index.aspx?langen-us 注意这里的CUDA版本&#xff0c;如未安装CUD…

破碎的像素地牢探险:游戏分享

软件介绍 《破碎的像素地牢》是开源一款地牢冒险探索类的游戏&#xff0c;融合了日系RPG经典风格&#xff0c;玩家将控制主角进行未知场景的探索。除了经典地牢玩法外&#xff0c;游戏还添加了更多创意内容&#xff0c;如黑屏状态前的挑战性等&#xff0c;使得游戏更加富有挑战…

Vue78-缓存路由组件

一、需求 路由切走的时候&#xff0c;组件会被销毁&#xff0c;路由切回来&#xff0c;组件被挂载&#xff01; 需要&#xff1a;路由切走的时候&#xff0c;组件不会被销毁。 二、代码实现 若是不加include属性&#xff0c;则在<router-view>里面展示的路由&#xff0c…

高通安卓12-Input子系统

1.Input输入子系统架构 Input Driver(Input设备驱动层)->Input core(输入子系统核心层)->Event handler(事件处理层)->User space(用户空间) 2.getevent获取Input事件的用法 getevent 指令用于获取android系统中 input 输入事件&#xff0c;比如获取按键上报信息、获…

深入理解Python中的并发与异步的结合使用

​ 在上一篇文章中&#xff0c;我们讨论了异步编程中的性能优化技巧&#xff0c;并简单介绍了trio和curio库。今天&#xff0c;我们将深入探讨如何将并发编程与异步编程结合使用&#xff0c;并详细讲解如何利用trio和curio库优化异步编程中的性能。 文章目录 并发与异步编程的区…

【数据结构与算法】二叉树的性质 详解

在二叉树的第i层上至多有多少个结点。 在二叉树的第 i 层上至多有 2 i − 1 2^{i-1} 2i−1 个结点(i≥1)。 深度为 K的二叉树至多有多少个结点。 深度为 k 的二叉树上至多含 2 k − 1 2^k - 1 2k−1 个结点(k≥1)。 在一颗二叉树中, 其叶子结点数n0和度为二的结点数n2之间…

安装CDH时报错:Parcel 不可用于操作系统分配 RHEL7,原因与解决办法~

报错信息&#xff1a; 解决办法与思路&#xff1a; 1、检查CDH包的后缀名称&#xff0c;Redhat与Centos安装时不需要修改后缀名称&#xff0c;麒麟系统安装时才需要修改。 2、目录里面需要有xxx.parcel xxx.parcel.sha manifest.json 三个文件 缺一不可&#xff08;注&#x…

Transformer预测 | 基于Transformer的锂电池寿命预测(Pytorch,CALCE数据集)

文章目录 文章概述模型描述程序设计参考资料文章概述 Pytorch实现基于Transformer 的锂电池寿命预测,环境为pytorch 1.8.0,pandas 0.24.2 随着充放电次数的增加,锂电池的性能逐渐下降。电池的性能可以用容量来表示,故寿命预测 (RUL) 可以定义如下: SOH(t)=CtC0100%, 其中,…

HarmonyOS Next 系列之可移动悬浮按钮实现(六)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…

MQ~消息队列能力、AMQP协议、现有选择(Kafka、RabbitMQ、RocketMQ 、Pulsar)

消息队列 消息队列看作是一个存放消息的容器&#xff0c;当我们需要使用消息的时候&#xff0c;直接从容器中取出消息供自己使用即可。由于队列 Queue 是一种先进先出的数据结构&#xff0c;所以消费消息时也是按照顺序来消费的。 常⽤的消息队列主要这 五 种&#xff0c;分别…

使用 DISPATCHERS 进行 Blueprint 之间的通信

文章目录 初始准备DISPATCHERS 的创建和绑定实现效果 初始准备 首先 UE5 默认是不提供 静态网格体编辑器也就是 Modeling Mode 的&#xff0c;这里需要从插件中添加 Modeling Tools Editor Mode 进入 Modeling Mode 模式&#xff0c;创建一个正方体 然后利用 PolyGroup Edit 和…

Vue79-路由组件独有的2个新的生命周期钩子

一、需求 news.vue路由组件被缓存了&#xff08;因为想要保留里面的输入框的数据&#xff01;&#xff09;&#xff0c;导致&#xff0c;路由页面切走&#xff0c;组件也不会被销毁&#xff0c;所以&#xff0c;beforeDestroy()函数就不会被执行&#xff0c;所以&#xff0c;定…

React+TS前台项目实战(十二)-- 全局常用组件Toast封装,以及rxjs和useReducer的使用

文章目录 前言Toast组件1. 功能分析2. 代码详细注释&#xff08;1&#xff09;建立一个reducer.ts文件&#xff0c;用于管理状态数据&#xff08;2&#xff09;自定义一个清除定时器的hook&#xff08;3&#xff09;使用rxjs封装全局变量管理hook&#xff08;4&#xff09;在to…

在scrapy中使用Selector提取数据

经院吉吉&#xff1a; 首先说明一下&#xff0c;在scrapy中使用选择器是基于Selector这个对象滴&#xff0c;selector对象在scrapy中通过XPATH或是CSS来提取数据的&#xff0c;我们可以自己创建selector对象&#xff0c;但在实际开发中我们不需要这样做&#xff0c;因为respons…

御道源码(ruoyi-vue-pro)个人使用小结

御道源码&#xff08;ruoyi-vue-pro&#xff09;个人使用小结 一、Git地址 1、平台项目简介及地址 2、开发指南&#xff0c;如图所示&#xff0c;部分功能需要收费&#xff0c;可自行了解 二、项目文件夹结构示例&#xff1a; 三、技术介绍 1.基于 Spring Boot MyBatis P…

dll丢失应该怎么解决,总结5种解决DLL丢失问题的方法

在数字时代&#xff0c;我们与计算机的每一天都密不可分。然而&#xff0c;就像所有技术产品一样&#xff0c;我们的计算设备也时不时地会出现一些问题&#xff0c;让人头疼不已。就在上周&#xff0c;我遭遇了一个令人崩溃的技术挑战——DLL文件丢失。这个看似微不足道的小问题…

【MySQL】 -- 事务

如果对表中的数据进行CRUD操作时&#xff0c;不加控制&#xff0c;会带来一些问题。 比如下面这种场景&#xff1a; 有一个tickets表&#xff0c;这个数据库被两个客户端机器A和B用时连接对此表进行操作。客户端A检查tickets表中还有一张票的时候&#xff0c;将票出售了&#x…

【Linux基础IO】深入理解缓冲区

缓冲区在文件操作的过程中是比较重要的&#xff0c;理解缓冲区向文件刷新内容的原理可以更好的帮助我们更深层的理解操作系统内核对文件的操作。 FILE 因为IO相关函数与系统调用接口对应&#xff0c;并且库函数封装系统调用&#xff0c;所以本质上&#xff0c;访问文件都是通过…

ES数值类型慢查询优化

现象 某个查询ES接口慢调用告警&#xff0c;如图&#xff0c;接口P999的耗时都在2500ms: 基本耗时都在查询ES阶段&#xff1a; 场景与ES设定 慢调用接口为输入多个条件分页查询&#xff0c;慢调用接口调用的ES索引为 express_order_info&#xff0c;该索引通过DTS(数据同步…