数据结构——堆排序

什么是堆排序

堆排序就是利用堆(假设利用大堆)进行排序的算法。他的基本思想是,将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将他移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。如此反复执行,便能得到一个有序序列了。

建堆 

首先我们需要对数组中元素int a[] = { 6,1,2,7,9,3,4,5,10,8 }建大堆。下面我们开始建堆。

向下调整 

 我们知道完全二叉树的孩子结点child=parent*2+1;我们建大堆就需要找大的结点的值。

我们假设左结点的值大,如果右节点a[child+1]>左节点a[child],那child=child+1;即

	while (){if (a[child + 1] > a[child]){child = child + 1;}}

接下来我们用child的值和父亲节点parent的值比较,如果,a[child]>a[parent],则交换这两个值,然后新的parent结点为child,新的child=新的parent*2+1,如果不满足这个条件的话,就跳出break。

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (){if (a[child + 1] > a[child]){child = child + 1;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

这个时候我们要判断这个循环什么时候停止,child每次和parent交换完都会child=parent*2+1;当child>n结点个数的时候就不需要继续再往下找大了,即循环停止。

while (child<n)

这个时候我们还需要考虑的是我们在找左节点和右节点中较大的值的时候,如果此时child==n的话,那child+1就会越界了。所以我们要加上限定条件child+1<n,即完整代码

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child<n){if (child + 1 < n && a[child + 1] > a[child]){child = child + 1;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

建大堆

这个时候我们已经完成了向下调整。此时我们只需要把数组中数据建大堆即可。

首先我们要先用for循环从最后一个结点开始找他的父节点和左右节点中大的与父节点比较,所以找的第一个父节点为(n-1)-1/2;i--,直到i>=0时一直向下调整建堆。

void HeapSort(int*a,int n)
{for (int i = (n - 1 - 1) / 2; i >= 0; i--)//建堆{AdjustDown(a, n, i);}}

这个时候大堆就已经建好了,此时堆顶元素是这个堆的最大值,我们用堆尾元素(end=n-1)与堆顶元素,此时最大值就来到了堆尾,然后继续向下调整保证前n-1个数还能保持大堆,再把end--,把最大的固定其位置,直到n=0时停止

int end = n - 1;
while (end > 0)
{Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;
}

测试

这个时候堆排序就完整的写完啦。我们测试运行。

int main()
{int a[] = { 6,1,2,7,9,3,4,5,10,8 };int n = sizeof(a) / sizeof(a[0]);for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");HeapSort(a, n);for (int i = 0; i < n; i++){printf("%d ", a[i]);}return 0;
}

复杂度

堆排序的效率到底有多高呢?我们来分析一下。它的运行时间主要消耗在初始构建堆和重建堆的反复筛选上。在构建堆的过程中,因为我们是完全二叉树从最下层最右边的非终端节点开始构建,将他与其孩子进行比较,若有必要进行交换,对于每个非终端结点来说,其实最多进行两次比较和呼唤操作,因次整个构建堆的时间复杂度为O(n)。

在正式排序时,第 i 次取堆顶记录重建堆需要用 O ( logi )的时间(完全二叉树的某个结点到根结点的距离为 (log i+1),并且需要取 n -1次堆顶记录,因此,重建堆的时间复杂度为 O ( nlogn )。
所以总体来说,堆排序的时间复杂度为 O ( nlogn )。由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为 O ( nlogn )。这在性能上显然要远远好过于冒泡、简单选择、直接插入的 O (n2)的时间复杂度了。
空间复杂度上,它只有一个用来交换的暂存单元,也非常的不错。不过由于记录的比较与交换是跳跃式进行的,因此堆排序也是一种不稳定的排序方法。
另外,由于初始构建堆所需的比较次数较多,因此,它并不适合待排序序列个数较少的情况。

源码

#include<stdio.h>void Swap(int* p1, int* p2)//交换
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void AdjustDown(int* a, int n, int parent)//向下调整
{int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child + 1] > a[child])//判断左右孩子较大的{child = child + 1;}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[] = { 6,1,2,7,9,3,4,5,10,8 };int n = sizeof(a) / sizeof(a[0]);for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");HeapSort(a, n);for (int i = 0; i < n; i++){printf("%d ", a[i]);}return 0;
}

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

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

相关文章

NVIDIA Jetpack6.0DP使用过程中的问题

Jetpack6.0DP是2023年12月才发布&#xff0c; 操作系统使用了ubuntu 22.04&#xff0c; gcc是11.4&#xff0c;版本都很高&#xff0c; 用起来还存在一些问题 无法使用jtop https://forums.developer.nvidia.com/t/jtop-no-longer-works-on-jp-6-0-dp/275215 使用$ sudo -H p…

常用网络接口自动化测试框架

(一&#xff09;GUI界面测试工具&#xff1a;jmeter 1、添加线程组 2、添加http请求 3、为线程组添加察看结果树 4、写入接口参数并运行 5、在查看结果树窗口查看结果 6、多组数据可增加CSVDataSetConfig(添加.csv格式的文件&#xff0c;并在参数值里以${x}格式写入) 此时变量…

条件随机场 (CRF) 的损失函数以及faiss 的原理介绍

1、条件随机场 (CRF) 的损失函数 条件随机场&#xff08;CRF&#xff09;是一种统计建模方法&#xff0c;常用于结构化预测问题&#xff0c;如序列标注、分词和命名实体识别等。在CRF模型中&#xff0c;损失函数用于衡量模型预测的标记序列与真实标记序列之间的差异。CRF的目标…

基于华为云解析服务实现网站区域封禁

前言 中国大陆以外的网络攻击不断&#xff0c;个人博客时常遭受不明个人或组织的攻击&#xff0c;给网站的安全运行带来了巨大的风险&#xff0c;同时DDoS、CC攻击等还会消耗服务器的资源&#xff0c;站长可能需要因此支付高昂的服务器、CDN的流量费用。 因此&#xff0c;如果…

【非关系型数据库】Redis概述及安装、命令使用

目录 前瞻 关系型数据库 非关系型数据库 关系型数据库和非关系型数据库区别 数据存储方式不同 扩展方式不同 对事务性的支持不同 非关系型数据库产生背景 总结 Redis简介 什么是Redis Redis具有的优点 Redis使用场景 哪些数据适合放入缓存中&#xff1f; Redis为什…

JAVAEE初阶相关内容第二十弹--HTTP协议【续集】

写在前&#xff1a;在前一篇博客中我们初步掌握了HTTP(超文本传输协议)的相关知识【点击跳转】&#xff0c;认识了HYYP协议的工作过程&#xff0c;掌握抓包工具Fiddler的使用。在“方法”中重点需要理解“GET”方法与“POST”方法的格式与内容&#xff0c;并了解了请求“报头”…

el-table 展开行表格,展开的内容高度可以变化时,导致的固定列错位的问题

问题描述 一个可展开的表格&#xff08;列设置了type“expand”&#xff09;&#xff0c;并且展开后的内容高度可以变化&#xff0c;会导致后面所有行的固定列错位&#xff0c;图如下&#xff0c;展示行中是一个树形表格&#xff0c;默认不展示子级&#xff0c;点击树形表格的…

彻底解决vue-video-player视频铺满div

需求 最近需要接入海康视频摄像头&#xff0c;然后把视频的画面接入到自己的网站系统中。以前对接过rtsp固定IP的显示视频&#xff0c;这次的不一样&#xff0c;没有了固定IP。海康的解决办法是&#xff0c;摄像头通过配置服务器到萤石云平台&#xff0c;然后购买企业版账号和…

Rocky9.3 安装MySQL后如何设置初始密码

Rocky9.3 安装MySQL后如何设置初始密码 启动MySQL服务查看临时密码设置新密码 启动MySQL服务 安装MySQL后需要看一下服务是否已经启动&#xff1a; systemctl status mysqld如果没有启动的话&#xff0c;需要先启动MySQL服务&#xff1a; systemctl start mysqld # 临时启动…

Spring Boot学习随笔- 集成MyBatis-Plus(二)条件查询QueryWrapper、聚合函数的使用、Lambda条件查询

学习视频&#xff1a;【编程不良人】Mybatis-Plus整合SpringBoot实战教程,提高的你开发效率,后端人员必备! 查询方法详解 普通查询 // 根据主键id去查询单个结果的。 Test public void selectById() {User user userMapper.selectById(1739970502337392641L);System.out.print…

Linux的基本指令(5)

目录 bc指令 uname指令 压缩解压相关的指令 zip指令 unzip指令 tar打包压缩指令 tar解压解包指令 ​编辑​编辑sz&rz 热键 关机命令 安装&#xff1a;yum install -y 指令 bc指令 bc命令可以很方便的进行浮点运算 Linux中的计算器 uname指令 语法&#xff1a;un…

春招冲刺第一天:Excel入门

春招冲刺第一天 前言&#xff1a; 转行换方向了家人们&#xff0c;准备往数据分析那转了&#xff0c;实习我现在也找不到&#xff0c;打算先猛学两周技术&#xff0c;过完年再投简历了。 时间确实非常紧张&#xff0c;目前一天计划学8小时以上&#xff0c;主要参考视频——&g…

从vue小白到高手,从一个内容管理网站开始实战开发第六天,登录功能后台功能设计--API项目中的登录实现(二),工厂模式创建数据库连接

一、回顾 在第五天的时候我们开始创建后台所以需项目,并创建项目所需要的相关实体类,具体内容没有掌握的小伙伴可以看点击下面的链接去学习。 从vue小白到高手,从一个内容管理网站开始实战开发第六天,登录功能后台功能设计--API项目中的登录实现(一)-CSDN博客文章浏览阅读…

uniappVue3版本中组件生命周期和页面生命周期的详细介绍

一、什么是生命周期&#xff1f; 生命周期有多重叫法&#xff0c;有叫生命周期函数的&#xff0c;也有叫生命周期钩子的&#xff0c;还有钩子函数的&#xff0c;其实都是代表&#xff0c;在 Vue 实例创建、更新和销毁的不同阶段触发的一组钩子函数&#xff0c;这些生命周期函数…

【java爬虫】首页显示沪深300指数走势图以及前后端整合部署方法

添加首页 本文我们将在首页添加沪深300指数成立以来的整体走势数据展示&#xff0c;最后的效果是这样的 单独贴一张沪深300整体走势图 我感觉从总体上来看指数还是比较稳的&#xff0c;没有特别大的波动&#xff0c;当然&#xff0c;这只是相对而言哈哈。 首先是前端页面 &l…

HarmonOS 通用组件(Button)

本文 我们来看看基础组件中的 Button 这是 ArkTS ui 原生支持的一个组件 用来创建不同样式的按钮 首先 我们还是创建一个最基本的组件结构 Entry Component struct Index {build() {Row() {Column() {}.width(100%)}.height(100%)} }我们可以在 Column 组件中 加入一个button…

【Electron】快速建立Vue3+Vite+Electron Ts项目

git https://github.com/electron-vite/electron-vite-vue 创建项目 npm create electron-vite or pnpm create electron-vite 初始化 pnpm install or pnpm i 启动项目 pnpm dev 打包项目 pnpm build 项目创建成功后默认情况下 窗口是H800 W600 在createWindow 函数…

亚马逊自养号测评:提升商品排名与流量的必要操作

自养号测评是通过使用自主注册的海外买家账号&#xff0c;对商品进行评价&#xff0c;以提升其在平台上的排名和流量的操作。卖家选择自养号这种方式来增强商品的曝光度和吸引更多潜在买家。然而&#xff0c;养号并非易事&#xff0c;需要卖家提高养号技术、掌握相应技巧&#…

java中list,map习题

&#x1f4d1;前言 本文主要是【java】——java中list,map习题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句…

dubbo的基础知识

dubbo是什么 Dubbo是一个分布式服务框架&#xff0c;是一种高性能的远程通讯框架。它提供了基于Java的RPC&#xff08;远程过程调用&#xff09;通信机制&#xff0c;使得应用之间可以方便地进行远程调用&#xff0c;实现分布式服务的调用和管理。Dubbo提供了服务注册、发现、负…