堆排序(C语言)

前言

        在上一篇内容:大小堆的实现(C语言),我们实现了关于创建大小堆的各函数与实现。但是如果突然要使用一个堆排序但是此时并没有一个现成的堆,这就需要花费时间去新建实现堆的插入删除这些操作从而实现一个堆,并且在插入的过程中存在内存空间的消耗(malloc空间),那是否有一些其它办法可以避免以上问题呢?

数组建堆

我们能不能不消耗空间就完成一次建堆?直接将所给的数组建堆可以吗?

这些数字在物理逻辑上是一个数组,而在虚拟逻辑上是一个完全二叉树,那么将这个完全二叉树进行一些调整后是不是就能得到一个堆呢?我们尝试利用之前的向上调整算法,完成建堆的操作:

上述操作的本质就是模拟堆插入的过程建堆

(第一个视为堆,第二个插入然后向上调堆、第一个和第二个视为堆,第三个插入然后向上调堆)

可以发现我们在没有申请内存空间的前提下,仅利用一个向上调整算法就完成了将数组建堆的操作,并最终到了一个小堆,但是如果我们在选出这个小堆中的最小值后,再想要选出这个堆中的次小值就会出现问题:

可以发现当要选出次小值时,缺少了”1“的小堆的剩余元素并不能算作是一个小堆它们都是无序的,所以为了选出次小值,我们还要建堆(将数组元素向上调整建堆)以此类推这就相当于选一次值就要建一次堆,那还不如直接选用时间复杂度为O(n)的暴力遍历数组选取最小值,次小值,而我们建堆的目的就是为了方便我们选出我们想要的最大/小、次大/小的数,但是很明显如果将利用向上调整算法建立一个小堆是无法满足我们的需求的,所以我们应该利用向上调整算法去建立一个大堆。

结论:若利用向上调整算法建小堆,如果取出最小值,那么剩下的数有可能不是堆,故应建大堆 

只需要该算法做一些调整,将(a[child] < a[parent])变为(a[child] > a[parent]),就可以建大堆:

调整后的结果是我们得到了一个大堆,此时即使将堆顶的“9”删除,剩余的两个子树也仍然是大堆的形式,这就意味着我们在选出最小数或次小数后只需要进行向下调整即可不需要考虑重新建堆,当我们想要最小值,只需要交换首尾元素的位置,取出此时的堆顶元素即可,想要获取次小值,只需要将尾部的数不再视为堆的一部分再次重复以上操作即可:

堆排序

其实上述的内容,就是我们实际中堆排序的一种实现方式,即利用向上调整算法建大堆然后再利用向下调整算法将挑选后剩余的元素重新调整为虚拟逻辑上的大堆以便下一次的选取

利用向上/下调整算法将数组中的数字在虚拟逻辑上重新变为大/小堆与重新建堆的区别是?

在堆排序算法中,我们需要构建一个最大/小堆来进行排序。这可以通过两种方式实现:

1. 重新建堆:这是一种直接的方法,从数组的首元素开始逐个插入到空堆中,步骤如下:

  • 创建一个空的堆
  • 将数组中的元素逐个插入到空堆中
  • 最终得到了一个满足最大(或最小)堆性质的完整二叉树

2. 向上/下调整:这是一种当已有部分构成的近似完全二叉树进行调整来达到目标状态的方法

  • 向上调整:从某节点开始,将其与父节点比较并交换位置,直至满足最大/小堆性质。该过程会将当前节点及其祖先节点推向正确位置,并保持子树仍然满足对应性质。
  • 向下调整:从某节点开始,将其与左右子节点比较并交换位置,直至满足最大/小堆性质。该过程会使当前节点及其后代子树变为有序树,并保持其他部分仍然满足对应性质

3、区别:

  1. 重新建堆是一种从零开始构建堆的方法,它将整个数组视为初始状态,并按顺序插入元素来构建最大(或最小)堆。这种方法需要较多的时间和空间复杂度。
  2. 向上调整和向下调整算法是在已有部分近似完全二叉树的基础上进行调整,通过比较节点与其父节点或子节点来达到维护最大(或最小)堆性质的目标。这两种算法可以在不重建完全二叉树的情况下对特定位置进行优化操作,因此具有更高效率。

4、总结:

  1. 如果已拥有一个无序数组并希望将其转换为一个满足最大/小堆性质的完全二叉树,则可以使用重新建堆方法
  2. 如果你已经拥有一个近似完全二叉树,并且只需对其中某些位置进行修正以满足最大(或最小)堆性质,则应使用向上调整或向下调整算法

利用向上调整算法实现堆排序

使用向上调整算法实现堆排序的步骤如下:

  1. 构建最大堆:从数组的第一个非叶子节点开始,依次对每个节点进行向上调整操作,使其满足最大堆性质。可以通过遍历非叶子节点并依次调用向上调整函数来完成这一步骤。

  2. 排序:将根节点(数组首元素)与末尾元素交换位置,并将末尾元素从堆中移除。然后对新的根节点进行一次向下调整操作,以维持最大堆性质。重复这个过程直到所有元素都被移除并排好序。

具体实现代码如下所示(假设数组是从索引 0 开始):

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>//向上调整,此时传递过来的是最后一个孩子的元素下标我们用child表示
void AdjustUP(HPDataType* a,int child)
{//由于我们要调整父亲与孩子的位置所以此时也需要父亲元素的下标,而0父亲元素的下标值 = (任意一个孩子的下标值-1)/ 2 int parent = (child - 1) / 2;//当孩子等于0的时位于树顶(数组首元素的位置),树顶元素没有父亲,循环结束while(child > 0){//如果孩子还未到顶且它的下标对应的元素值小于它的父亲的下标对应的元素值,就将父子位置交换,交换玩后还要将下标对应的值“向上移动”//if (a[child] < a[parent])if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}//由于这是一个小堆,所以当孩子大于等于父亲时不需要交换,直接退出循环即可else{break;}}
}//向下调整算法
void AdjustDown(HPDataType* a, int size, int parent)
{//根据之前的推论,左孩子的下标值为父亲下标值的两倍+1,左孩子的下标值为父亲下标值的两倍+2int child = parent * 2 + 1;//循环结束的条件是走到叶子结点while (child < size){//假设左孩子小,若假设失败则更新child,转换为右孩子小,同时保证child的下标不会越界//if (child + 1 < size && a[child + 1] < a[child])if (child + 1< size && a[child + 1] > a[child]){++child;}if (a[child] < a[parent]){//如果此时满足孩子小于父亲则交换父子位置,同时令父亲的下标变为此时的儿子所在下标,儿子所在下标变为自己的儿子所在的下标(向下递归)Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}//如果父亲小于等于左孩子就证明删除后形成的新堆是一个小堆,不再需要向下调整算法,循环结束else{break;}}
}//堆排序
void HeapSort(int* a, int n)
{//构建大堆for (int i = 1; i < n; i++){AdjustUP(a, i);}//排序int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}}int main()
{int a[] = { 4,6,2,1,5,8,2,9 };HeapSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}//HeapSort(a, i);return 0;
}

利用向下调整算法实现堆排序

1、从最后一个结点的父亲开始向下调整

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>//向下调整算法
void AdjustDown(HPDataType* a, int size, int parent)
{//根据之前的推论,左孩子的下标值为父亲下标值的两倍+1,左孩子的下标值为父亲下标值的两倍+2int child = parent * 2 + 1;//循环结束的条件是走到叶子结点while (child < size){//假设左孩子小,若假设失败则更新child,转换为右孩子小,同时保证child的下标不会越界if (child + 1< size && a[child + 1] < a[child]){++child;}if (a[child] < a[parent]){//如果此时满足孩子小于父亲则交换父子位置,同时令父亲的下标变为此时的儿子所在下标,儿子所在下标变为自己的儿子所在的下标(向下递归)Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}//如果父亲小于等于左孩子就证明删除后形成的新堆是一个小堆,不再需要向下调整算法,循环结束else{break;}}
}//堆排序
void HeapSort(int* a, int n)
{//构建最小堆for(int i = (n-1-1)/2;i>=0;--i){AdjustDown(a,n,i);}//排序int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}}int main()
{int a[] = { 4,6,2,1,5,8,2,9 };HeapSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}//HeapSort(a, i);return 0;
}

~over~

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

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

相关文章

51单片机应用从零开始(十)·指针

指针 C语言指针是一种保存变量地址的数据类型。它可以让程序直接访问内存中的数据&#xff0c;而不需要通过变量名来访问。指针变量存储的是一个地址&#xff0c;这个地址指向内存中的某个位置&#xff0c;该位置存储了一个值。 在C语言中&#xff0c;可以使用&运算符取得一…

Endnote加入新的style(参考文献格式)

1. 下载模板 可以从官网上下载模板&#xff0c;比如某些常见的期刊都有自己的模板&#xff0c;还有写中文论文的话有专门的GBT7714。 2. 示范 以下图MDPI为例&#xff0c;下载下来是一个ens文件。 双击打开此文件 file -> save as 输入保存的名字&#xff0c;我这里保…

字符串转换整数

字符串转换整数 描述 : 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 myAtoi(string s) 的算法如下&#xff1a; 读入字符串并丢弃无用的前导空格检查下一个字符&am…

Linux:docker镜像的创建(5)

1.基于已有镜像创建 步骤&#xff1a; 1.将原始镜像加入容器并运行 2.在原始镜像中部署各种服务 3.退出容器 4.使用下面命令将容器生成新的镜像 现在我们在这个容器里做了一些配置&#xff0c;我们要把他做成自己镜像 docker commit -m "centos7_123" -a "tarr…

【工具使用-Audition】如何使用Audition查看频率

一&#xff0c;简介 在工作过程中要对处理后的音频进行频率分析&#xff0c;本文以Audition 2020为例进行说明&#xff0c;供参考。 二&#xff0c;操作步骤 2.1 生成测试音源 使用Audition生成左通道为1KHz&#xff0c;右通道为10KHz的音源信号 如图所示&#xff1a; 2.…

Android Init系统:引领设备启动的先锋

Android Init系统&#xff1a;引领设备启动的先锋 引言 Init系统是一个操作系统启动的必要组件&#xff0c;负责在启动时初始化所有系统资源、服务和应用程序。在Android设备中&#xff0c;Init系统起到了至关重要的作用&#xff0c;它是启动过程中的第一个进程&#xff0c;负…

学习知识回顾随笔(远程连接MySQL|远程访问Django|HTTP协议|Web框架)

文章目录 如何远程连接MySQL数据库1.创建用户来运行&#xff0c;此用户从任何主机连接到mysql数据库2.使用IP地址来访问MySQL数据库 如何远程访问Django项目Web应用什么是Web应用应用程序的两种模式Web应用程序的优缺点 HTTP协议&#xff08;超文本传输协议&#xff09;简介HTT…

C++-模板

目录 一.泛型编程 二.模板的分类 三.函数模板 1.函数模板的概念 2.函数模板格式 3.函数模板的原理 4.函数模板的实例化 a.隐式实例化 b.显式实例化 5.模板参数的匹配原则 四.类模板 1.类模板的定义格式 2.类模板的实例化 五.class和typename的区别 六.非类型模板…

路由策略,gRPC 路由如何实现

目录 一、为啥我们要路由策略&#xff1a; 二、基于gRPC 路由策略 一、为啥我们要路由策略&#xff1a; 我们可以重新回到调用方发起 RPC 调用的流程。在 RPC 发起真实请求的时候&#xff0c;有一个步骤就是从服务提供方节点集合里面选择一个合适的节点&#xff08;就是我们…

C++基础 -37- 模板函数与普通函数调用规则

当模板函数比普通函数更好匹配形参的时候&#xff0c;会优先调用模板函数 #include "iostream"using namespace std;template <class T> void show(T a, T b) {cout << a << endl;cout << b << endl;cout << "temp show&…

Matlab论文插图绘制模板第129期—函数网格曲面图

在之前的文章中&#xff0c;分享了Matlab函数折线图的绘制模板&#xff1a; 函数三维折线图&#xff1a; 进一步&#xff0c;再来分享一下函数网格曲面图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自…

Unity DOTS《群体战斗弹幕游戏》核心技术分析之3D角色动画

最近DOTS发布了正式的版本, 我们来分享现在流行基于群体战斗的弹幕类游戏&#xff0c;实现的核心原理。今天给大家介绍大规模战斗群体3D角色的动画如何来实现。 DOTS 对角色动画支持的局限性 截止到Unity DOTS发布的版本1.0.16,目前还是无法很好的支持3D角色动画。在DOTS 的b…

陷同质化“高端”悖论,良品铺子降价应对,沃隆食品IPO已终止

撰稿|行星 来源|贝多财经 坚持“高端零食”战略多年的良品铺子&#xff0c;脱下了自己的“长衫”。 近日&#xff0c;良品铺子&#xff08;SH.603719&#xff09;仅上任三天的董事长、总经理杨银芬在全员公开信中表示&#xff0c;该品牌将实施17年来最大规模降价&#xff0c…

oops-framework框架 之 界面管理(三)

引擎&#xff1a; CocosCreator 3.8.0 环境&#xff1a; Mac Gitee: oops-game-kit 注&#xff1a; 作者dgflash的oops-framework框架QQ群&#xff1a; 628575875 回顾 在上文中主要通过oops-game-kit大家了一个新的模版项目&#xff0c; 主要注意项是resources目录下的两个文…

TS版LangChain实战:基于文档的增强检索(RAG) | 京东云技术团队

LangChain LangChain是一个以 LLM &#xff08;大语言模型&#xff09;模型为核心的开发框架&#xff0c;LangChain的主要特性&#xff1a; 可以连接多种数据源&#xff0c;比如网页链接、本地PDF文件、向量数据库等允许语言模型与其环境交互封装了Model I/O&#xff08;输入…

【力扣206】反转链表

【力扣206】反转链表 一.题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1 &#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2 &#xff1a; 输入&#xff1a;head [1,2] 输出&#x…

码云配置遇到秘钥不正确

你这个就是秘钥没有和git绑定&#xff0c; 需要 git config --global user.name "你的用户名随便写" git config --global user.email "你的邮箱"

阿里云租赁费用_阿里云服务器多配置报价表

阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、轻量应用服务器2核2G3M带宽轻量服务器一年87元&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;ECS云服务器e系列2核2G配置99元一年、2核4G配置365元一年、2核8G配置522元一年…

跨网文件摆渡系统:安全、可控的数字传输桥梁

在企业高度信息化的时代&#xff0c;数据的流通与共享已经成为企业、组织乃至个人之间不可或缺的沟通方式。然而&#xff0c;在数据流通的过程中&#xff0c;我们经常会遇到各种难题和挑战&#xff0c;尤其是当涉及到不同网络环境之间的文件传输。这不仅需要保证文件的安全性&a…

销售员需练好的基本功有哪些?该如何培养?

销售员需练好的基本功有哪些&#xff1f;该如何培养&#xff1f; 作为销售人员&#xff0c;以下是一些需要练好的基本功&#xff0c;以及培养这些基本功的方法&#xff1a; 1. 良好的沟通技巧&#xff1a;销售员需要具备清晰、简洁、礼貌和自信的语言表达能力&#xff0c;能够…