【数据结构】_堆排序问题

news/2025/2/11 17:07:19/

目录

1. 基于建堆的堆排序(需调HPPush)

2. 基于原数组的堆排序(仅调AdjustUp)

3. 堆排序建堆与升降序的总结


在专栏前文中,已经实现了堆的基本结构与相关方法;(小根堆)

详见下文:

数据结构】_堆的实现-CSDN博客文章浏览阅读429次,点赞19次,收藏8次。专栏前文中,已经介绍了入堆及向上调整算法,出堆及向下调整算法,详情见下文:实际对于整除运算parent = (child - 1) / 2,parent并不会小于0,但当parent=0时,若a[parent] > a[child],则再次进行child与parent的更新,使得parent与child均为0。当parent=0时,若若a[parent] > a[child],则再次进行child与parent的更新,使得child更新为0,下次则无法进入while循环;https://blog.csdn.net/m0_63299495/article/details/145521676https://blog.csdn.net/m0_63299495/article/details/145521676修改向上调整与向下调整的比较逻辑,将堆修改为大根堆

1. 基于建堆的堆排序(需调HPPush)

当前堆为大根堆,通过对数组元素逐个push进行建堆,再使用HPPop依次出堆顶元素,最终实现对原数组元素的降序排序:

#define _CRT_SECURE_NO_WARNINGS
#include"Heap.h"
void TestHeap1() {int a[] = { 4,2,8,1,5,6,9,7 };HP hp;HPInit(&hp);// 输出原始数组printf("orignal array: \n");for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++) {printf("%d ", a[i]);}printf("\n");// 建立小根堆,输出其顺序存储for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++) {HPPush(&hp, a[i]);}printf("minHeap array: \n");HPPrint(&hp);// 对原始数组使用堆排序,进行升序输出int i = 0;while (!HPEmpty(&hp)) {//printf("%d ", HPTop(&hp));a[i++] = HPTop(&hp);HPPop(&hp);}printf("Ascending sort: \n");for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++) {printf("%d ", a[i]);}printf("\n");HPDestory(&hp);
}
int main() {TestHeap1();return 0;
}

输出结果如下: 

注:1、这种排序思路为实现排序需要额外开辟空间建堆,因为其调用了HPPush方法,空间复杂度为O(N);

2、实现打印升序与降序只需修改向上调整和向下调整方法的对比大小关系,即可实现大根堆的降序和小根堆的升序排序:

2. 基于原数组的堆排序(仅调AdjustUp)

1、回顾已实现的Adjust方法:

void AdjustUp(HPDataType* a, int child);

其参数为数组与新插元素的下标,直接将数组视为一个完全二叉树,并不需要依赖于HPPush方法,故并不额外开辟空间,空间复杂度为O(1);

现不调用HPPush方法,即对于已知数组不建堆,基于原数组仅调用向上调整算法进行堆排序

2、以大根堆为例,调用AdjustUp方法后,在原数组上已经实现了大根堆的顺序存储(但并未申请额外空间),考虑其输出升降序问题:

(1)若想要实现降序排序:

调用AdjustUp方法后,当前数组已满足首元素为最大元素,则输出并删除堆顶的最大元素后,接下来需在剩下的元素中建新大根堆并再删除堆顶最大元素,这与初始考虑的直接删除堆顶元素的HPPop方法思路一致,会导致节点关系的错位与混乱,如此循环往复建堆与调整,虽可以实现最终的排序效果,但显然非常麻烦;

(2)若想要实现升序排序:

调用AdjustUp方法后,当前数组已满足首元素为最大元素,将堆顶元素与最末结点元素交换,再将其位置确定在数组尾,即现确定了最大的元素且保持原堆的大根堆基本关系与结构不变,再进行向下调整即可。如此循环,每次都确定未排序元素中最大的结点,并将其依次从后向前定位在数组中,从而实现了升序排序;

#define _CRT_SECURE_NO_WARNINGS
#include"Heap.h"
// 测试不建堆的排序
void HeapSort(int* a, int n) {// 建堆for (int i = 1; i < n; i++) {AdjustUp(a, i);}// 打印大根堆的顺序存储序列printf("maxHeap array: \n");for (size_t i = 0; i < n; i++) {printf("%d ", a[i]);}printf("\n");// 交换首尾并删尾,再进行向下调整int end = n - 1;while (end>0) {Swap(&a[0], &a[end]);AdjustDown(a, end,0);end--;}// 打印升序排序结果printf("Ascending sort: \n");for (int i = 0; i < n; i++) {printf("%d ", a[i]);}printf("\n");
}
int main() {int a[] = { 4,2,8,1,5,6,9,7 };int sz = sizeof(a) / sizeof(a[0]);HeapSort(a,sz);return 0;
}

 运行程序,结果为:

3. 堆排序建堆与升降序的总结

对于实现堆排序:

1、若采用先建堆再排序的方法,则建大根堆实现降序,建小根堆实现升序;(通常不用)

(1)这种方式需要调用HPPush方法,HPPush方法内部自行调用AdjustUp方法,并使用HPTop方法获取堆顶元素并逐个pop以实现降序或升序输出;

(2)这种方式的空间复杂度为O(N);(较高)

2、若采用不建堆直接排序的方法,则建大根堆实现升序,小根堆实现降序;(常用)

(1)这种方式无需调用HPPush方法,直接调用AdjustUp方法,将原数组处理为小根堆或大根堆的顺序存储序列,交换首尾元素并确定尾元素位置后,对其余元素调用AdjustDown方法再确认倒数第二个元素的位置,循环进行直至形成降序或升序排列;

(2)这种方式的时间复杂度为O(N*log N);(较低)


http://www.ppmy.cn/news/1571203.html

相关文章

PHP E-mail发送机制详解

PHP E-mail发送机制详解 引言 随着互联网的普及&#xff0c;电子邮件&#xff08;E-mail&#xff09;已经成为人们日常工作中不可或缺的通信工具。PHP作为一种流行的服务器端脚本语言&#xff0c;也提供了丰富的E-mail发送功能。本文将详细介绍PHP E-mail发送的机制&#xff…

备战蓝桥杯:双指针(滑动窗口)算法之逛花展

P1638 逛画展 - 洛谷 | 计算机科学教育新生态 这道题我们只要用一个kind和一个mp[N]的数组就能解决了 我们的解法1就是暴力枚举&#xff0c;先固定2&#xff0c;从2开始找连续的满足所有种类的最短的子数组&#xff0c;然后固定5&#xff0c;3&#xff0c;1&#xff0c;3&…

[css] 黑白主题切换

link动态引入 类名切换 css滤镜 var 类名切换 v-bind css预处理器mixin类名切换 【前端知识分享】CSS主题切换方案

Open-Interface:基于大语言模型 LLM 的自动化界面操作系统

开放式界面助手 核心原理 这是一个基于大语言模型(LLM)的自动化界面操作系统。它通过截取屏幕画面&#xff0c;将用户需求转化为具体的鼠标键盘操作指令&#xff0c;并能实时监控执行效果进行修正。整个系统采用模块化设计&#xff0c;实现了从用户输入到界面操作的完整闭环。 …

RapidrepairDaoImpl

目录 1、 RapidrepairDaoImpl 1.1、 maintenanceNum 1.2、 updateListReceptione 1.2.1、 //派工状态 1.2.2、 //领料状态 1.2.3、 // 主表保存成功 1.2.4、 // 维修明细表 1.2.5、 // 费用明细表有数据 1.2.6、 // 保险理赔明细 1.2.7、 // 三包索赔明细 …

uniapp实现人脸识别(不使用三方插件)

uniapp实现人脸识别 内容简介功能实现上传身份证进行人脸比对 遇到的问题 内容简介 1.拍摄/相册将身份证照片上传到接口进行图片解析 2.使用live-pusher组件拍摄人脸照片&#xff0c;上传接口与身份证人脸进行比对 功能实现 上传身份证 先看下效果 点击按钮调用chooseImage…

3.攻防世界 unseping(反序列化与魔术方法)

进入题目页面如下 给出源码&#xff0c;开始代码审计 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;方便调试和查看代码结构 highlight_file(__FILE__);// 定义一个名为 ease 的类 class ease {// 定义私有属性 $method&#xff0c;用于存储要调用的方法名private …

20240824 美团 笔试

文章目录 1、单选题1.11.21.31.41.51.61.71.81.91.101.111.121.131.141.151.161.171.181.191.202、编程题2.12.2岗位:硬件开发工程师(嵌入式系统软件开发方向) 题型:20 道单选题,2 道编程题题 1、单选题 1.1 C 语言中,如果输入整数 v 是 2 的幂,下面表达式中哪个会返…