堆排序讲解

news2024/11/26 22:35:06

前言

在讲堆的删除时,我们发现一步一步删除堆顶的数据,排列起来呈现出排序的规律,所以本节小编将带领大家进一步理解堆排序。

1.堆排序概念

那么什么是堆排序?

堆排序(Heap Sort)是一种基于堆数据结构的排序算法。它利用堆的性质(大堆或小堆)进行排序操作。堆排序的基本思想是通过构建堆,将待排序的数组转化为一个符合堆性质的堆结构,然后不断将堆顶元素与堆的最后一个元素进行交换,并调整堆,使剩余元素继续满足堆的性质。重复这个过程,直到整个数组有序。

堆排序的步骤如下:

  1. 构建大堆或小堆:将待排序的数组视为一个完全二叉树,通过从最后一个非叶子节点开始,依次对每个节点进行向下调整(Adjustdown)操作,构建出一个大堆或小堆。这个过程确保了堆的性质:对于大堆,父节点的值大于等于其子节点的值;对于小堆,父节点的值小于等于其子节点的值。
  2. 排序:交换堆顶元素(最大值或最小值)与堆的最后一个元素,并将堆的大小减一。然后对堆顶元素进行向下调整,使剩余元素继续满足堆的性质。重复这个过程,直到堆的大小为1,即所有元素都已经排好序。(运用堆删除的思想
  3. 得到排序结果:经过上述步骤,数组中的元素就按照升序(从小到大)或降序(从大到小)排列了。

堆排序的时间复杂度为 O(nlogn),其中 n 是待排序数组的大小。它具有原地排序的特点,不需要额外的存储空间。

堆排序的优点是稳定性较好,适用于大规模数据的排序。然而,堆排序的缺点是相对较慢,尤其在快速排序等其他排序算法的应用场景中,堆排序的性能可能不如其他算法。

2.堆的建立方法

2.1向下调整建立堆(补充)

在这里,堆的建立有两种,在二叉树的顺序结构中提到一种建堆的方法,通过尾插再进行向上调整,不过时间复杂度为O(N*logN),这里提供新的建堆方法,通过向下调整法,时间复杂度为O(N),不过再用此调整方法时,左右子树要是堆的结构。即从倒数的第一个非叶子结点的子树开始调整,一直调整到根结点的树,就可以调整成堆。

假设给一个数组 int a[]={4,2,8,1,5,6,9,7,2,7,9},通过向下调整法制造大堆。

2.2向上调整法

通过比较新插入元素与其父节点的值来判断是否需要进行交换。如果新插入元素的值大于父节点的值,就将它们进行交换,并更新索引值。这样,逐步向上调整,直到新插入元素找到了合适的位置,保证了堆的性质。

//向上调整
void Adjustup(Datatype* a,int child) {
	int parent = (child - 1) / 2;
	while (child > 0) {
		if (a[child] > a[parent]) {
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}

2.3建堆时间复杂度分析

1.向下调整法

void Adjustdown(Datatype* 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;
		
	}
}

2.向上调整法
向上调整法每层节点向上调整次数就是乘以层数
//向上调整
void Adjustup(Datatype* a,int child) {
	int parent = (child - 1) / 2;
	while (child > 0) {
		if (a[child] > a[parent]) {
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}

注意:上述代码都是采用建大堆的代码,建小堆把部分大于符号改成小于。
因此向下调整法实质上是节点数少的层,调整次数越多,向上调整是节点数越多,调整次数越多。

3.排序建堆选择

升序:建大堆
降序:建小堆
每次将堆首元素与尾元素交换,然后向下调整,每交换一次,堆的大小要减一,因为我们是每次将最大或者最小的元素依次交换堆后面。
例如升序的一个过程如下图:
void HeapSort(int* a, int n)
{
	//降序,建小堆
	// 升序,建大堆
	//for (int i = 1; i < n; i++)
	//{
	//	Adjustup(a, i);
	//}
	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;
	}
}

void TestHeap2()
{
	int a[] = {20,17,16,5,3,4 };
	HeapSort(a, sizeof(a) / sizeof(int));
	for (int i = 0; i < sizeof(a) / sizeof(int); i++) {
		printf("%d ", a[i]);
	}
}

4.TOP-K问题

TOP-K 问题:即求数据结合中前 K 个最大的元素或者最小的元素,一般情况下数据量都比较大
比如:专业前 10 名、世界 500 强、富豪榜、游戏中前 100 的活跃玩家等。
对于 Top-K 问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了 ( 可能数据都不能一下子全部加载到内存中) 。最佳的方式就是用堆来解决,基本思路如下:
1. 用数据集合中前 K 个元素来建堆
前k个最大的元素,则建小堆
前k个最小的元素,则建大堆
2. 用剩余的 N-K 个元素依次与堆顶元素来比较,不满足则替换堆顶元素
将剩余 N-K 个元素依次与堆顶元素比完之后,堆中剩余的 K 个元素就是所求的前 K 个最小或者最大的元素。
假如求一堆数中的前k个最小的数,则建大堆。
这里我们采用随机数来生成100个随机数,然后存入一个动态数组中,然后选出前10个最小的数。
void PrintTopK(int* a, int n, int k)
{
	// 1. 建堆--用a中前k个元素建堆
	for (int i = (k - 1 - 1) / 2; i >= 0; i--) {
		Adjustdown(a, k, i);
	}
	// 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换
	for (int j = n - k; j < n; j++) {
		if (a[j] < a[0]) {
			a[0] = a[j];
			Adjustdown(a, k, 0);
		}
	}
	printf("最小前%d个数:", k);
	for (int i = 0; i < k; i++) {
		printf("%d ", a[i]);
	}
}
void TestTopk()
{
	int n = 100;
	int* a = (int*)malloc(sizeof(int) * n);
	srand(time(0));
	for (size_t i = 0; i < n; ++i)
	{
		a[i] = rand() % 100;
	}
	PrintTopK(a, n, 10);
	}

本节内容到此结束,谢谢各位友友的捧场,下节小编将带领大家继续了解二叉树的链式存储结构!!!

留下三连和评论吧!!!

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

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

相关文章

如何从 Android 图库中恢复误删除的照片

如果您正在阅读这篇文章&#xff0c;那么您肯定意外地从 Android 设备中删除了照片。并且您正在寻找一种简单的方法来恢复 Android 图库中已删除的照片。 从图库恢复已删除的照片 随着技术的进步&#xff0c;现在使用单个设备&#xff08;即 Android 手机&#xff09;&#xf…

vue27:脚手架详细介绍main.js

在 Vue.js 中&#xff0c;render 函数是一个可选的选项&#xff0c;它允许你自定义组件的渲染逻辑。 如果你没有在 Vue 实例中提供 render 函数&#xff0c;Vue 将使用模板&#xff08;template&#xff09;来生成虚拟 DOM。 以下是render / template 两种方式的比较&#…

C++ Qt实现http url启动本地应用程序

更多Qt文章,请访问《深入浅出C++ Qt开发技术专栏》:https://blog.csdn.net/yao_hou/category_9276099.html 文章目录 1、注册自定义协议2、编写web页面3、编写C++应用程序我们在使用腾讯会议时经常会通过http链接打开本地的腾讯会议,例如下图: 打开会议发起人给的链接,会出…

Python代码大使用Paramiko轻松判断文件类型,提取上级目录

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、Paramiko简介 Paramiko是一个用于SSHv2协议的Python实现&#xff0c;提供了客户端和服务器功能。它可以用于远程连接和管理服务器&#xff0c;执行命令、上传下载文件等。本文将介绍如何使用Paramiko判断文件类…

树莓派4B 零起点(二) 树莓派 更换软件源和软件仓库

目录 一、准备工作&#xff0c;查看自己的树莓派版本 二、安装HTTPS支持 三、更换为清华源 1、更换Debian软件源 2&#xff0c;更换Raspberrypi软件仓库 四、进行软件更新 接前章&#xff0c;我们的树莓派已经启动起来了&#xff0c;接下来要干的事那就是更换软件源和软件…

LeetCode ---400周赛

题目列表 3168. 候诊室中的最少椅子数 3169. 无需开会的工作日 3170. 删除星号以后字典序最小的字符串 3171. 找到按位与最接近 K 的子数组 一、候诊室中的最少椅子数 简单的模拟题&#xff0c;我们可以这样来模拟&#xff1a;当有顾客来时&#xff0c;我们加一把椅子&…

java并发控制(猴子摘桃例子)

【问题】 有n个桃子&#xff0c; 猴子A每次固定摘2个&#xff0c;猴子B每次固定摘3个&#xff0c;这2只猴子不断摘桃子直到剩余桃子数量不足以摘&#xff08;必须满足摘桃个数&#xff09;&#xff1b; 【1】 使用AtomicInteger&#xff08;推荐&#xff09; 1&#xff09;利…

11 深入理解Linux文件系统与日志分析

目录 11.1 深入理解Linux文件系统 11.1.1 inode与block详解 1. inode和block概述 2. inode的内容 3. inode的号码 4. inode的大小 11.1.2 硬链接与软连接 1. 硬链接 2. 软连接 11.1.3 EXT类型文件恢复 1. 编译安装extundelete 2. 模拟删除并执行恢复操作 11.1.4 xfs类型文件备…

【Centos】深度解析:CentOS下安装pip的完整指南

【Centos】深度解析&#xff1a;CentOS下安装pip的完整指南 大家好 我是寸铁&#x1f44a; 总结了一篇【Centos】深度解析&#xff1a;CentOS下安装pip的完整指南✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 方式1(推荐) 下载get-pip.py到本地 sudo wget https://bootstrap.p…

用python编撰一个电脑清理程序

自制一个电脑清理程序&#xff0c;有啥用呢&#xff1f;在电脑不装有清理软件的时候&#xff0c;可以解决自己电脑内存不足的情况。 1、设想需要删除指定文件夹中的临时文件和缓存文件。以下是代码。 import os import shutil def clean_folder(folder_path): for root,…

CleanMyMac X 4.15.4破解版含2024最新CleanMyMac激活码

CleanMyMac X 4.15.4 for Mac 2023最新中文激活版是一款mac电脑清理工具&#xff0c;可让您快速轻松地个性化您的 Mac 操作系统。此外&#xff0c;它提高了系统速度和性能&#xff0c;帮助你远离黑客和垃圾文件。该程序具有尖端工具和功能&#xff0c;能够清除Mac系统中的任何故…

利用SuperGlue算法实现跨尺度金字塔特征点的高效匹配(含py代码)

在计算机视觉领域&#xff0c;特征点匹配是一个基础而关键的任务&#xff0c;广泛应用于图像拼接、三维重建、目标跟踪等方向。传统的特征点匹配方法通常基于相同尺度下提取的特征进行匹配&#xff0c;然而在实际场景中&#xff0c;由于成像距离、分辨率等因素的差异&#xff0…

图像处理ASIC设计方法 笔记29 场景自适应校正算法

P152 7.2.3 场景自适应校正算法 (一)Scribner提出的神经网络非均匀性校正算法 非均匀性校正(Non-Uniformity Correction,简称NUC)算法是红外成像技术中非常重要的一个环节。它主要用于校正红外焦平面阵列(Infrared Focal Plane Arrays,简称IRFPA)中的固定模式噪声,以提…

《python程序语言设计》2018版第5章第46题均值和标准方差-下部(本来想和大家说抱歉,但成功了)

接上回&#xff0c;5.46题如何的标准方差 本来想和大家说非常抱歉各位同学们。我没有找到通过一个循环完成两个结果的代码。 但我逐步往下的写&#xff0c;我终于成功了&#xff01;&#xff01; 这是我大前天在单位找到的公式里。x上面带一横是平均值。 我不能用函数的办法…

高考后志愿填报信息采集系统制作指南

在高考的硝烟散去之后&#xff0c;每位学生都面临着一个重要的任务——志愿填报。老师们如何高效、准确地收集和整理这些信息&#xff0c;成为了一个棘手的问题。难道我们只能依赖传统的手工登记方式&#xff0c;忍受其繁琐和易错吗&#xff1f; 易查分是一个简单易用的在线工具…

基于GTX 8B10B编码的自定义PHY上板测试(高速收发器十四)

前文整理了GTX IP&#xff0c;完成了自定义PHY协议的收发模块设计&#xff0c;本文将通过光纤回环&#xff0c;对这些模块上板测试&#xff0c;首先需要编写一个用于生成测试数据的用户模块。 1、测试数据生成模块 本模块用于生成自定义PHY协议的测试数据&#xff0c;通过axi_…

XUbuntu24.04之ch9344(usb转串口芯片)安装驱动(二百四十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

DVB-S系统发射端Matlab仿真及FPGA实现

DVB标准 Digital Video Broadcasting&#xff08;数字视频广播&#xff09;是一个完整的数字电视解决方案&#xff0c;其中包括DVB-C&#xff08;数字电视有线传输标准&#xff09;&#xff0c; DVB-T&#xff08;数字电视地面传输标准&#xff09;&#xff0c;DVB-S&#xff…

什么是突发性耳聋?

72小时内突然发生、原因不明的感音神经性听力损失&#xff0c;至少在相邻的两个频率听力下降≥20dBHL。 特点&#xff1a; 1发生在数分钟、数小时或3天以内的听力下降&#xff1b; 2原因不明&#xff1b; 3多发生于单侧&#xff0c;可伴有耳鸣、耳堵塞感及耳周麻木感&#…

C#操作MySQL从入门到精通(21)——删除数据

前言: 谈到数据库,大家最容易脱口而出的就是增删改查,本文就是来详细介绍如何删除数据。 本文测试使用的数据库如下: 1、删除部分数据 使用delete 关键字,并且搭配where条件使用,否则会导致表中数据全部被删除 string sql = string.Empty;if (radioButton_DeletePart…