堆排序 详解+图解

news2024/10/7 8:23:20

 堆排序是一种基于堆数据结构的排序算法,它的基本思想是将待排序序列构造成一个最大堆,然后将堆顶元素和堆底元素交换,再把堆的大小减一,使堆顶元素下沉到合适的位置,重复以上操作,直到整个序列有序。

堆排序分为两个基本操作:建堆和排序。建堆的过程是把无序序列构建成一个堆,这个过程从最后一个非叶子节点开始,依次将每个节点和其子节点构成一个小堆或大堆。排序的过程是将堆顶元素和堆底元素交换,然后把堆的大小减一,使堆顶元素下沉到合适的位置,重复直到堆的大小变为1为止,最终得到一个从小到大排序的序列。

堆排序的时间复杂度为O(nlogn),空间复杂度为O(1)。它是一种不稳定的排序算法,但由于它的时间复杂度比较稳定,因此在大规模数据排序时表现优秀。

交换排序:堆排序(不稳定的排序)
堆排序是一种树形选择排序,是对直接选择排序的有效改进。

堆是一个完全二叉树,可以分为最大堆和最小堆两种。最大堆的每个父节点都比它的子节点大,而最小堆的每个父节点都比它的子节点小。

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

堆排序的时间复杂度为O(nlogn),最坏情况下也是O(nlogn),空间复杂度为O(1)。但它的常数因子较大,实际使用时可能不如快速排序和归并排序。

大根堆 87,45,78,32,17,65,53,9 可以看成
                    87
            45                78
        32        17        65        53
    9
    也就相当于是完全二叉树

下面来看一下代码该如何实现

首先是主要思路

void heapsort(int a[], int sz)
{
	buildmaxheap(a, sz);//初始建堆
	int i = 0;
	int temp = 0;
	for (i = sz-1; i > 1; i--)//n-1趟的交换和建堆过程
	{
		temp = a[i];
		a[i] = a[1];
		a[1] = temp;
		headajust(a, 1, i - 1);//把剩余的i-1个元素调整成堆
	}
}

建大根堆的代码是这样的👇

void buildmaxheap(int a[], int  sz)
{
	int i = 0;
	for (i = sz / 2; i > 0; i--)//从i=a[sz/2]~1,反复调整堆
		headajust(a, i, sz);
}

将元素传入以元素k为根的子树进行调整👇

void headajust(int a[], int k, int sz)
{
	int i = 0;
	a[0] = a[k];//暂存子树的根结点
	for (i = k * 2; i <= sz; i *= 2)//沿较大的子结点向下筛选
	{
		if (i < sz && a[i] < a[i + 1])//指向最大的孩子结点
			i++;
		if (a[0] >= a[i])
			break;
		else
		{
			a[k] = a[i];//将a[i]调整到双亲结点上
			k = i;//修改k的值,以便继续向下筛选
		}
	}
	a[k] = a[0];//被筛选的结点的值放入最终位置
}

完整测试代码

#include<stdio.h>
void headajust(int a[], int k, int sz)
{
	int i = 0;
	a[0] = a[k];//暂存子树的根结点
	for (i = k * 2; i <= sz; i *= 2)//沿较大的子结点向下筛选
	{
		if (i < sz && a[i] < a[i + 1])//指向最大的孩子结点
			i++;
		if (a[0] >= a[i])
			break;
		else
		{
			a[k] = a[i];//将a[i]调整到双亲结点上
			k = i;//修改k的值,以便继续向下筛选
		}
	}
	a[k] = a[0];//被筛选的结点的值放入最终位置
}
void buildmaxheap(int a[], int  sz)
{
	int i = 0;
	for (i = sz / 2; i > 0; i--)//从i=a[sz/2]~1,反复调整堆
		headajust(a, i, sz);
}
void heapsort(int a[], int sz)
{
	buildmaxheap(a, sz);//初始建堆
	int i = 0;
	int temp = 0;
	for (i = sz-1; i > 1; i--)//n-1趟的交换和建堆过程
	{
		temp = a[i];
		a[i] = a[1];
		a[1] = temp;
		headajust(a, 1, i - 1);//把剩余的i-1个元素调整成堆
	}
}
int main()
{
		int a[] = { 0,49,38,65,97,76,13,27 };
		int sz = sizeof(a) / sizeof(a[0]);
		int j = 0;
		printf("原始待排序的数组为:");
		for(j = 1; j < sz; j++)
			printf("%d ", a[j]);
		heapsort(a,sz);
		printf("\n堆排序后的数组为:");
		for (j = 1; j < sz; j++)
			printf("%d ", a[j]);
	return 0;
}

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

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

相关文章

【QT】事件分发器

event事件分发器&#xff0c;用于分发事件&#xff0c;在这里也可以做拦截&#xff0c;返回值boo。如果返回的是true代表拦截处理&#xff0c;不再向下分发。 展示事件拦截 上一段代码&#xff1a;【QT】鼠标常用事件-CSDN博客 代码 // 事件分发器 // 拦截鼠标按下 // QEven…

Unity地面交互效果——2、动态法线贴图实现轨迹效果

Unity引擎动态法线贴图制作球滚动轨迹 大家好&#xff0c;我是阿赵。   之前说了一个使用局部UV采样来实现轨迹的方法。这一篇在之前的基础上&#xff0c;使用法线贴图进行凹凸轨迹的绘制。 一、实现的目标 先来回顾一下&#xff0c;上一篇最终我们已经绘制了一个轨迹的贴图…

第五章 I/O管理 七、设备的分配与回收

目录 一、设备分配时应该考虑的因素 1、设备的固有属性 2、设备分配算法 3、设备分配中的安全性 &#xff08;1&#xff09;安全分配方式: 优点: 缺点: &#xff08;2&#xff09;不安全分配方式: 优点: 缺点: 4、静态分配 5、动态分配 二、设备分配管理中的数据结…

一个非常实用的Python模块-struct模块

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 struct模块提供了用于在字节字符串和Python原生数据类型之间转换函数&#xff0c;比如数字和字符串。 该模块作用是完成Python数值和C语言结构体的Python字符串形…

【git】git拉取代码报错,fatal: refusing to merge unrelated histories问题解决

大家好&#xff0c;我是好学的小师弟。今天准备将之前写的代码&#xff0c;拉到新的工程文件夹(仓库)下面&#xff0c;用了pull命令&#xff0c;结果报错了&#xff0c;报错截图如下 $ git pull https://gitee.com/* #仓库地址 fatal: refusing to merge unrelated histor…

自动化测试注意事项

什么是自动化测&#xff1f; 做测试好几年了&#xff0c;真正学习和实践自动化测试一年&#xff0c;自我感觉这一个年中收获许多。一直想动笔写一篇文章分享自动化测试实践中的一些经验。终于决定花点时间来做这件事儿。 首先理清自动化测试的概念&#xff0c;广义上来讲&#…

数据库-扩展语句,约束方式

扩展语句&#xff1a; 例&#xff1a; 自增长&#xff1a; auto_increment:表示该字段可以自增长&#xff0c;默认从一开始&#xff0c;每条记录会自动递增1 复制&#xff1a; 通过like这个语法直接复制ky32的表结构&#xff0c;只能复制表结构&#xff0c;不能复制表里面的…

C语言每日一题(23)兔子的序列

牛客网 BC159 兔子的序列 题目描述 描述 兔子发现了一个数字序列&#xff0c;于是开始研究这个序列。兔子觉得一个序列应该需要有一个命名&#xff0c;命名应该要与这个序列有关。由于兔子十分讨厌完全平方数&#xff0c;所以兔子开创了一个新的命名方式&#xff1a;这个序列…

Linux--文件操作

1.什么是文件 对于文件来说&#xff0c;文件文件内容文件属性&#xff1b;对于文件来说&#xff0c;只有两种操作&#xff0c;对内容的修改和对文件属性的修改&#xff0c;这就是文件的范畴。 对于存放在磁盘上的文件&#xff0c;我们需要通过进程来进行访问&#xff0c;访问文…

数据库 用户管理与授权

数据库的数据管理 DDL: CTEATE DROP ALTER dml:对数据进行管理 update insert into delete truncate dql:查询语询select dcl:权限控制语句grant revoke 数据库用户管理: 创建用户 修改用户的权限 删除用户。 grant要在终端执行。 create user ‘ky32’localhost ide…

紧急:发现NGINX Ingress Controller for Kubernetes中的新安全漏洞

导语 大家好&#xff0c;今天我要向大家紧急报告一则消息&#xff1a;我们在NGINX Ingress Controller for Kubernetes中发现了三个新的安全漏洞&#xff01;这些漏洞可能被黑客利用&#xff0c;从集群中窃取机密凭据。在本文中&#xff0c;我们将详细介绍这些漏洞的细节&#…

日本it培训就职 日本的IT工作以什么为主?

现在有好多非计算机专业的人转行做赴日程序员&#xff0c;为什么这么一批人要千里迢迢跑到日本去当程序员呢&#xff1f;当然是因为日本程序员缺口大&#xff0c;需要的人才多&#xff0c;而且日本对程序员的要求不像国内要求那么高&#xff0c;比较硬性的要求就是学历至少要在…

PCIe 访问 EP 配置空间,空间映射详解,BDF 计算偏移

访问 EP 的配置空间方法 内存映射IO 访问 内存访问配置空间 前置知识 PCIe 设备的寻址是按照 BDF 即 Bus-Device-Function 来组织的。访问某个设备则需要根据BDF计算偏移地址。 两种不同的内存访问配置空间方法 类 xilinx&#xff0c;基地址 偏移地址访问 // linux-5.10\…

node使用fs模块(三)—— fs模块的其他使用(复制文件、文件的重命名和移动、删除)

文章目录 前言一、fs的复制1.方式一(先读取后写入)2.方式二&#xff08;流式读取写入)3.两种方式的区别 二、文件的重命名和移动&#xff08;fs.rename&#xff09;1. 参数2. 基本使用&#xff08;文件的重命名&#xff09;3. 基本使用&#xff08;文件的移动&#xff09;4.文件…

13.7性能测试工具(LoadRunner)(简单扫盲)

下载LoadRunner和360极速浏览器 一.为什么选择LoadRunner而不是Jmeter 1.Jmeter没有录制功能. 2.LoadRunner可以设计非常丰富的测试场景. 3.LoadRunner能够产出非常丰富的测试报告. 二.LoadRunner三大组件 1.VUG: 功能: 录制脚本(编写脚本). 2.Controller: 功能: 设计场…

RocketMQ生产者消息发送出去了,消费者一直接收不到怎么办?(Rocket MQ订阅关系一致性)

问题: 使用RocketMQ消息队列&#xff0c;生产者将数据发送出去了&#xff0c;但是生产者一致没接收到&#xff08;或者是间隔好几分钟&#xff0c;突然接收到一条数据&#xff09;怎么办&#xff1f;并且通过rocket web控制台查看消息的状态为NOT_ONELINE或者NOT_CONSUME&#…

把Qt6.2.4内置的标签打印了一遍

2023年10月31日&#xff0c;周二晚上 #include <QGridLayout> #include <QPushButton> #include <QLabel> #include <QApplication> #include <QStyle>int main(int argc, char *argv[]) {QApplication a(argc, argv);QWidget widget;widget.set…

SpringBoot -- 请求数据多态映射(jackson)

有些情况下&#xff0c;服务端提供了一个抽象类及其多个实现类&#xff0c;当前端传递 json 数据到后端时&#xff0c;我们希望映射得到的对象数据是根据某个特征区分开的具体的实现类对象。 文章目录 实现方式示例抽象类对象若干实现类测试接口及前端传递请求体接参结果 JsonT…

JavaScript的高级概述

还记得我们刚刚开始的时候给JavaScript的定义吗&#xff1f; JavaScript是一种高级的&#xff0c;面向对象的&#xff0c;多范式变成语言&#xff01; 这种定义JavaScript只是冰山一角&#xff01; JavaScript的高级定义 JavaScript是一种高级的、基于原型的、面向对象、多范…

node使用fs模块(二)—— 读取文件的基本使用(普通读取、同步读取等、流式读取)

文章目录 一、读取文件1. 参数说明2. 基本使用3.读取文件的同步和异步 二、流式文件写入&#xff08;fs.appendFile&#xff09;1. 参数说明2.基本使用 一、读取文件 1. 参数说明 参数1&#xff1a; path——读取的文件路径&#xff08;必填&#xff09; 参数2&#xff1a; op…