排序——堆排序

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

目录

什么是堆?

堆排序

堆排序的思想

堆排代码

向下调整算法

 堆排整体


什么是堆?

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

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

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

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

如图数组就是一个小堆

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

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

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

如图:

堆排序

堆排序的思想

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

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

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

不知道向下调整算法可以去回顾本节:堆——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.hqwc.cn/news/519882.html

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

相关文章

Linux文件描述符剖析

文章目录 文件描述符文件描述符分配规则重定向软硬链接软链接&#xff08;Symbolic Link&#xff09;&#xff1a;硬链接&#xff08;Hard Link&#xff09;&#xff1a; 文件描述符 文件描述符&#xff08;File Descriptor&#xff09;是一个非负整数&#xff0c;用于标识打开…

智能控制:物联网智能插座对接文档

介绍 一开始买的某米的插座&#xff0c;但是好像接口不开放&#xff0c;所以找到了这个插座&#xff0c;然后自己开发了下&#xff0c;用接口控制插座开关。wifi的连接方式&#xff0c;通电后一般几秒后就会连接上wifi&#xff0c;这个时候通过接口发送命令给他。 产品图片 通…

C++11线程同步之条件变量

C11线程同步之条件变量 condition_variable成员函数生产者和消费者模型 condition_variable_any成员函数生产者和消费者模型 条件变量是C11提供的另外一种用于 等待的同步机制&#xff0c;它能阻塞一个或多个线程&#xff0c;直到收到另外一个线程发出的通知或者超时时&#x…

ROS 2基础概念#5:执行器(Executor)| ROS 2学习笔记

在ROS 2中&#xff0c;Executor是一个核心概念&#xff0c;负责管理节点&#xff08;Node&#xff09;中的回调函数&#xff0c;如订阅消息的回调、服务请求的回调、定时器回调等。Executor决定了何时以及如何执行这些回调&#xff0c;从而在ROS 2系统中实现异步编程。 ROS 2 …

vscode自定义插件的开发过程记录

前言 本文是关于visual studio code软件上自定义插件的开发记录&#xff0c;将从头记录本人开发的过程&#xff0c;虽然网上也有很多文章&#xff0c;但个人在实践的过程还是会遇到不一样的问题&#xff0c;所以记录下来&#xff0c;以便于后期参考。 前期准备&#xff1a; 1、…

STL之list容器代码详解

1 基础概念 功能&#xff1a; 将数据进行链式存储 链表&#xff08;list&#xff09;是一种物理存储单元上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接实现的 链表的组成&#xff1a;链表由一系列结点组成。 结点的组成&#xff1a;一个是存储数…

嵌入式学习第二十五天!(网络的概念、UDP编程)

网络&#xff1a; 可以用来&#xff1a;数据传输、数据共享 1. 网络协议模型&#xff1a; 1. OSI协议模型&#xff1a; 应用层实际收发的数据表示层发送的数据是否加密会话层是否建立会话连接传输层数据传输的方式&#xff08;数据包&#xff0c;流式&#xff09;网络层数据的…

HelpLook VS GitBook:知识库优劣详解

在信息爆炸的时代&#xff0c;企业要保持竞争优势&#xff0c;就必须善于管理和利用内部的知识资产。企业知识库作为一种集中存储和共享知识的工具&#xff0c;正在成为现代企业不可或缺的一部分。 HelpLook和Gitbook是提供专业知识库的两个平台&#xff0c;也被大众熟知。它们…

一文读懂HDMI的演变-从HDMI1.0到HDMI2.1(建议收藏)

HDMI&#xff0c;全称为&#xff08;High Definition Multimedia Interface&#xff09;高清多媒体接口&#xff0c;主要用于传输高清音视频信号。 HDMI System HDMI系统包括HDMI的source和HDMI的sink, 其中source 是源端&#xff0c;即信号的来源&#xff1b;Sink的接收端&a…

什么是以人为本的AI?

AI技术蓬勃发展&#xff0c;有望极大改善我们的日常生活。因此&#xff0c;人工智能专家经常围绕在我们社会中利用人工智能的最佳方式展开对话&#xff0c;并由此得出了以人为中心的AI方法。以人为中心的AI意为不是用机器代替人类&#xff0c;而是用机器来优化人类的体验。 在…

乌鸡的身高

解法&#xff1a; 只需要看身高最高的乌鸡个数是否>2.若满足则除去当前这只乌鸡的最高身高都是最高身高。 若不满足则只需要看最高的和第二高的乌鸡。 #include<iostream> #include<vector> #include<algorithm> #include<cmath> using namespac…

图像检索与识别——词袋模型(Bag-of-features models)

一、定义 计算机视觉单词袋是一种描述计算图像之间相似度的技术&#xff0c;常用于用于图像分类当中。该方法起源于文本检索&#xff08;信息检索&#xff09;&#xff0c;是对NLP“单词袋”算法的扩展。在“单词袋”中&#xff0c;我们扫描整个文档&#xff0c;并保留文档中出…