堆排序实现详解

堆排序算法详解与C代码实现 在众多的排序算法中,堆排序以其独特的性质和高效的性能脱颖而出。堆排序算法利用堆这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组来模拟堆的结构以进行排序。堆排序可以分为两个主要的过程:建堆和堆调整。 阅读详情

title: 堆排序
date: 2024-05-21 12:26:10
tags: 七大排序 堆排序 排序
cover: https://picbed0521.oss-cn-shanghai.aliyuncs.com/blogpic/heapsort.png


原文见我的网站: www.supdriver.top

背景知识

  • 知道什么是大堆/小堆
  • 掌握如何将数组与完全二叉树的映射关系
  • 掌握向上调整法和向下调整法

大堆/小堆

大堆的特性:每一个节点的值都比左右孩子都大,根的值是整个大堆中最大的
小堆的特性:每一个节点的值都比左右孩子都小,根的值是整个大堆中最小的

后面以大堆为例

数组映射成完全二叉树

任何一个数组可以看成一个完全二叉树,下标0为二叉树的根

而非常方便的是,已知一个节点的下标,可以利用数学关系求出根或孩子的下标

下标关系如下(变量均为下标)

  • parent = (child-1)/2
  • left_child = parent*2+1
  • right_child = parent*2+2

建堆方法

向上调整法

在已有一个大堆的前提下,把一个新的数据插入到堆的最后一个节点(此时破坏大堆的结构),再一路向上调整,可以重新建堆

template<class T>
void adjust_up(vector<T>& arr, int child)
{
	int parent = (child - 1) / 2;
	while (parent != child)//parent == child == 0时
	{
		if (arr[parent] < arr[child])//不满足大堆
		{
			swap(arr[parent], arr[child]);//交换
			child = parent;//继续向上调整,迭代child和parent
			parent = (child - 1) / 2;
		}
		else//完成建堆,退出循环
		{
			break;
		}
	}
}

向下调整法

在已有一个大堆的前提下,把根的值改变(此时破坏大堆的结构),再一路向下调整,可以重新建堆

上一句也可以等价于,左子树和右子树都是大堆的前提下,将根一路向下调整,可以重新建堆

template<class T>
void adjust_down(vector<T>& arr,int sz , int parent)
{
	int child = parent * 2 + 1;
	if (child + 1 < sz && arr[child + 1] > arr[child]) child++;//取较大的孩子

	while (child < sz)
	{
		if (arr[parent] < arr[child])
		{
			swap(arr[parent], arr[child]);
			parent = child;
			int child = parent * 2 + 1;
			if (child >= sz) break;
			if (child + 1 < sz && arr[child + 1] > arr[child]) child++;
		}
		else
		{
			break;
		}
	}
}

主要思路

建堆

用向上调整法和向下调整法都能建堆,不过向上调整法建堆思路更简单,也更容易代码实现,只需要把第一个元素当成现成的大堆,然后逐个插入并向上调整。也就是说只需要写一个循环

//向上调整法建堆
for (int i = 1; i < sz; i++)
{
    adjust_up(arr, i);//逐个插入并向上调整建堆
}

排序

此时的排序有个特点,那就是我们要倒着排

尽管此时数组的第一个元素为最大值,似乎只需要把它放在那,整一个降序排列,再把剩下的元素建个堆,确定第二大的数…但是,此时有个很大的问题,当把剩下的元素看作堆时,会发现前面建堆留下来的关系全被打乱了(原本父子关系,兄弟关系乱套了),也就是说要完全重新建堆,极大地浪费了第一次建堆所建立的关系

所以我们要尽可能保留原来的堆,既然把下标0处的节点除外会极大地影响堆的关系,那就改成把最后一个叶子节点除外,这样对原来的堆几乎没有改变。

但建堆选出的最大的的值在根处,所以把根和最后一个叶子节点交换,交换后,此时待排序的数中的最大值以完成排序(即倒着排),把最后一个叶子节点从堆中除外,再从根开始一路向下调整即可重新建堆,如此循环

	for (int i = sz-1; i >= 1; i--)//利用i的减小将已排序的元素逐个除外
	{
		swap(arr[0], arr[i]);//选出最大的元素放在末尾
		adjust_down(arr,i,0);//向下调整建堆,待排序的(待建堆的)数的个数为i,逐个减小
	}

正因为实际上排序时是倒着排的,所以当我们要排序时:

  • 升序->大堆
  • 降序->小堆

全部代码

#include <vector>
using namespace std;

template<class T>
void adjust_up(vector<T>& arr, int child)
{
	int parent = (child - 1) / 2;
	while (parent != child)//parent == child == 0时
	{
		if (arr[parent] < arr[child])//不满足大堆
		{
			swap(arr[parent], arr[child]);//交换
			child = parent;//继续向上调整,迭代child和parent
			parent = (child - 1) / 2;
		}
		else//完成建堆,退出循环
		{
			break;
		}
	}
}

template<class T>
void adjust_down(vector<T>& arr,int sz , int parent)
{
	int child = parent * 2 + 1;
	if (child + 1 < sz && arr[child + 1] > arr[child]) child++;//取较大的孩子

	while (child < sz)
	{
		if (arr[parent] < arr[child])
		{
			swap(arr[parent], arr[child]);
			parent = child;
			int child = parent * 2 + 1;
			if (child >= sz) break;
			if (child + 1 < sz && arr[child + 1] > arr[child]) child++;
		}
		else
		{
			break;
		}
	}
}

template <class T>
void heap_sort(vector<T>& arr)
{
	int sz = arr.size();

	//建堆
	for (int i = 1; i < sz; i++)
	{
		adjust_up(arr, i);//逐个插入并向上调整建堆
	}

	for (int i = sz-1; i >= 1; i--)
	{
		swap(arr[0], arr[i]);//选出最大的元素放在末尾
		adjust_down(arr,i,0);//向下调整建堆
	}
}
堆排序算法详解及实现 堆排序的核心是构建一个最大堆或最小堆,并利用堆的特性进行排序。最大堆是指父节点的值大于或等于其子节点的值,最小堆则相反,父节点的值小于或等于其子节点的值。从最后一个非叶子节点开始,对每个节点进行堆化操作,即将当前节点与其子节点进行比较并交换,直到满足最大堆的性质。排序:将最大堆的根节点(即数组的第一个元素)与最后一个叶子节点进行交换,并从堆中移除该节点。然后,对新的根节点进行堆化操作,重复此步骤,直到堆为空。堆排序是一种高效的排序算法,本文将详细介绍堆排序的原理,并给出相应的源代码实现。 阅读详情

相关推荐

JavaScript堆排序算法详解与实战实现

在数据结构和算法设计中,堆作为一种特殊的完全二叉树结构,广泛应用于优先级队列、排序、图算法等领域。其中,大顶堆(Max Heap)与小顶堆(Min Heap)是堆结构的两种基本形态,它们通过不同的极值约束条件实现对元素访问顺序的控制。本章将深入剖析这两种堆的数学定义、结构性质、操作机制及其在实际场景中的差异性应用,并借助形式化语言、代码示例与可视化流程图全面揭示其内在逻辑。堆的本质是一种满足特定有序性质的完全二叉树。所谓“完全”,是指除最后一层外,其余各层节点均满;

weixin_29041443的博客 1102

堆排序原理与Python实现详解

堆排序是一种基于完全二叉树结构的高效排序算法,它通过构建大顶堆或小顶堆来实现排序。下面我将从算法原理、时间复杂度、Python实现和可视化演示等方面进行全面讲解。堆是一种特殊的完全二叉树,分为两种类型:在堆排序中,我们通常使用大顶堆来进行升序排序,因为大顶堆的根节点总是最大值。堆排序主要分为两个阶段:具体的执行流程如下:堆调整(Heapify)是堆排序的核心操作,它确保父节点的值大于子节点的值: 2. 完整的Python实现 下面是堆排序的完整Python代码实现: 3. 算法执行过程详解 3.

qq_43108684的博客 453

Microduck机器鸭开源AI项目:本地部署与模型微调实战指南

开源AI模型的本地化部署与定制化训练正成为开发者关注的技术趋势。与依赖云端API的在线服务不同,本地部署允许用户将模型权重下载至自有GPU环境,通过命令行或WebUI完成推理、批量任务处理及API集成,在数据隐私、离线使用和接口稳定性方面具备天然优势。模型微调则基于预训练权重,利用领域数据训练特定任务,从而提升生成质量与业务适配度。这一技术路径广泛应用于内容生成、智能对话、自动标注等场景,尤其适合消费级显卡开发者、数据敏感型团队及二次开发研究者。Microduck(机器鸭)作为近期预售火爆的开源项目,围绕“

weixin_29082143的博客 414

堆排序详解以及java实现_Java实现的二叉堆以及堆排序详解

非完全二叉树三、二叉堆插入节点和删除节点(一)、插入节点思路:因为二叉堆是用数组来存储数据的,所以每次插入节点时,实际是往数组数据尾部增加数据。但是,如果直接往尾部放数据,有可能破坏【父节点键值大于或等于子节点】的特性,因此,每次插入数据时都需要将二叉堆从新堆化的操作。堆化过程就是插入节点和父节的键值进行比较,如果父节点键值小于插入节点,则需要将两个节点进行交换,然后继续向上比较,直至父节点不小于...

weixin_32367173的博客 167

2019年数学建模美赛经验总结

北京时间2019年1月29号上午9时,数模美赛结束。美赛结束已经10多天了,我在这次竞赛中负责建模和编程,趁现在记忆还比较清晰,写下这篇博客记录第一次参加数学建模美赛的经历。 补更:2019年4月20日公布成绩,笔者最终获得了美赛一等奖 目录 1、基本情况 2、选题 3、分工合作 4、论文写作 5、建模 6、编程 7、入门资源 ...

Smallactive 7万+

HTML5网页基础设计——课程介绍专栏

案例: 参考代码: <!doctype html> <html> <head> <meta charset="utf-8"> <title>动手实践</title> <style> *{ margin: 0; padding: 0; font-size:14px; } dd{ width: 461px; height: 145px; margin: -4px; pad.

shengming_tutou的博客 4594

【排序算法】堆排序详解与实现

堆排序的时间复杂度为O(N*logN) (向下建堆时间复杂度为O(N),排序时间复杂度为O(N*logN)), 空间复杂度:O(1) ,稳定性:不稳定。

m0_74265792的博客 1231

多智能体强化学习论文——SEAC(NIPS 2020)

存在的问题&研究动机&研究思路 在稀疏奖励的环境下,多智能体的exploration存在效率不足等问题。 在IAC的基础上尝试加入重要性采样,使得每次更新智能体iii的参数时,不再仅仅使用智能体iii的数据,而是使用所有智能体的数据进行智能体iii数据的更新。 对于原始的IAC算法是on-policy的,而SEAC则是off-poligy的。 创新点 在每个智能体iii的actoriactor_iactori​和criticicritic_icritici​的更新过程中,都加入了重要性

我的AI笔记 1207

堆排序详解以及java实现_堆排序详解以及java实现

堆堆排序和合并排序一样,是一种时间复杂度为O(nlgn)的算法,同时和插入排序一样,是一种就地排序算法(不需要额外的存储空间)。堆排序需要用到一种被称为最大堆的数据结构,与java或者lisp的gc不一样,这里的堆是一种数据结构,他可以被视为一种完全二叉树,即树里面除了最后一层其他层都是填满的。也正是因为这样,树里面每个节点的子女和双亲节点的序号都可以根据当前节点的序号直接求出。Parent(i)...

weixin_35651102的博客 143

gnss变形监测基础(四)

监测站的数据采样率指的是监测站在单位时间内收集数据的频率,通常以赫兹(Hz)为单位。在GNSS变形监测中,数据采样率决定了监测系统能够捕捉到的变形动态变化的详细程度和时间分辨率。例如,一个采样率为1Hz的GNSS监测站意味着它每秒钟收集一次位置数据;而一个采样率为10Hz的监测站则每秒钟收集10次位置数据。较高的采样率能够提供更细致的时间序列数据,有助于分析快速变化的动态过程,如地震活动或建筑物的振动响应。然而,较高的采样率也意味着数据量更大,可能需要更多的存储空间和更强大的数据处理能力。

我的博客 1293

PyTorch深度学习实战(2)——PyTorch基础

PyTorch 是广泛应用于机器学习领域中的强大开源框架,因其易用性和高效性备受青睐。在本节中,将介绍使用 PyTorch 构建神经网络的基础知识。首先了解 PyTorch 的核心数据类型——张量对象。然后,我们将深入研究用于张量对象的各种操作。PyTorch 提供了许多帮助构建神经网络的高级方法及组件,并提供了利用 GPU 更快地训练神经网络的张量对象。

盼小辉丶的博客 5万+

堆排序原理详解和代码实现

堆是利用完全二叉树大根堆:每个节点的值都大于等于其左右孩子的值。小根堆:每个节点的值都小于等于其左右孩子的值。

dawn191228的博客 991

RSL-RL:开源人形机器人强化学习控制研究库

摘要:RSL-RL是一款专为机器人领域设计的开源强化学习库,其核心特点是紧凑性、可修改性和高性能。该库聚焦PPO和BC两大主流算法,并整合了对称性增强、好奇心驱动等机器人专用技术。通过纯GPU训练优化,RSL-RL在大型仿真中展现出卓越的吞吐性能,已成功应用于腿足运动控制、全身协调等多个机器人研究场景。其轻量级架构包含运行器、算法和网络三个可独立修改的组件,支持TensorBoard等主流日志工具。该框架特别适合需要快速原型开发的机器人研究者,但不适用于通用机器学习基准测试。开源地址:https://git

2506_90492529的博客 1676

堆排序算法详解、及Java实现

堆排序 需要提前掌握:二叉树、顺序存储二叉树 概述 堆:堆可以看做是一个完全二叉树 大顶堆:其父节点总是大于等于子节点的值,而左右子节点之间没有大小顺序要求 小顶堆:其父节点总是小于等于子节点的值,而左右子节点之间没有大小顺序要求 堆排序:是指利用堆这种数据结构所设计的一种排序算法。以大顶堆为例,我们知道:完全二叉树可以以顺序方式存入数组中的,而大顶堆的根节点是堆中最大的数据,则可以将根节点和最后一个元素交换,再忽略其存在,将前面的元素再次构建成大顶堆,如此反复即可完成排序。 一般,升序采用大顶堆,降序

博客 312

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

堆排序详解:从原理到实现

堆是一种特殊的完全二叉树,分为大顶堆和小顶堆两种类型,分别适用于升序和降序排序。建堆的核心算法包括向上调整(O(logn))和向下调整(O(logn)),其中向下调整建堆效率更高(O(n))。堆排序通过构建大顶堆、交换堆顶与末尾元素并重复调整,实现O(nlogn)时间复杂度的高效排序,且空间复杂度为O(1)。该算法不仅用于排序,还广泛应用于优先级队列、Top-K问题等场景,其关键在于掌握调整算法和从最后一个非叶子节点开始建堆的优化策略。

fantasy5_5的博客 1106

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

堆排序详解及其代码实现

堆排序 1、整体思想 利用完全二叉树构建大顶堆。 完全二叉树必须从上到下,从左到右进行构建,这也保证了完全二叉树如果有孩子一定有左孩子 大顶堆:父节点的值大于或等于其左右孩子的值 堆顶元素和堆底元素进行互换,堆底元素不再参与构建 重复上面的步骤 2、构建大顶堆 2.1、由数组构建完全二叉树 注意这个构建只是思路上的构建,实际上并不需要对数组做任何的操作。数组仍是那个数组,只是我们访问数组的形式发生了改变,我们把这个数组当成一颗完全二叉树然后用访问完全二叉树的方式访问数组。 2.2、由完全二叉树构建大顶

admin3335的博客 847

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

java实现堆排序算法详解

前端时间树还没整明白呢,所以写排序的时候就没有写堆排序,现在补上 排序原理 1.大顶堆和小顶堆的定义: 大顶堆:每个节点的子节点都小于其父节点 小顶堆:每个节点的子节点都大于其父节点 2.排序思想 以从小到大为例 1)将待排序序列构造成一个大顶堆 2)此时,整个序列的最大值就是堆顶的根节点 3)将其与末尾元素进行交换,此时末尾就为最大值 4)将剩下的n-1个元素重复此操作 3.图解说明 以序列4,6,8,5,9为例 步骤一:得到一个大顶堆 步骤二:将堆顶元素与末尾元素进行交换,使末尾元素最大,然后

weixin_44015485的博客 466

Java实现的二叉堆以及堆排序详解

一、前言   二叉堆是一个特殊的堆,其本质是一棵完全二叉树,可用数组来存储数据,如果根节点在数组的下标位置为1,那么当前节点n的左子节点为2n,有子节点在数组中的下标位置为2n+1。二叉堆类型分为最大堆(大顶堆)和最小堆(小顶堆),其分类是根据父节点和子节点的大小来决定的,在二叉堆中父节点总是大于或等于子节点,该二叉堆成为最大堆,相反地称之为最小堆。因此,最大堆父节点键值大于或等于子节点,最小堆父节点键值小于或等于子节点。根据二叉堆的特点,二叉堆可以用来实现排序、有限队列等。堆排序就是利用二叉堆的特性来实现

rianple的博客 350

详解堆排序(python实现)

堆排序之python实现 1.首先要知道什么是堆: 简单来说 堆就是一颗完全二叉树,如下图这样,通俗的讲除了最后一个有孩子的节点可以有一个左孩子或者有左右两个孩子,其他有孩子的节点都必须有左右两个孩子。 完全二叉树在列表里面的存储顺序:tree_list=[1,2,3,4,5,6,7,8,9,10,11,12] 即从上至下 从左到右顺序存储 堆分为最大堆和最小堆: 1.最大堆:所有节点的值都比它的左右孩子节点值大,这就造成整个堆最大值必然在根节点。 2.最小堆:所有节点的值都比它的左右孩子节点值小,这就造

Game__Zero的博客 1708

c语言内部堆排序的实现,内部排序之堆排序的实现详解

堆排序(Heap Sort)只需要一个记录大小的辅助空间,每个待排序的记录仅占有一个存储空间。(1)基本概念a)堆:设有n个元素的序列:{k1, k2, ..., kn}对所有的i=1,2,...,(int)(n/2),当满足下面关系:ki≤k2i,ki≤k2i+1或 ki≥k2i,ki≥k2i+1这样的序列称为堆。堆的两种类型:根结点最小的堆----小根堆。根结点最大的堆-...

weixin_33756596的博客 260

Java实现堆排序算法详解及优化

同时,我们探讨了堆排序的优化方法,包括使用更小的辅助空间,以提高其性能。堆排序通过将数组构建成一个最大堆,然后重复地将堆顶元素与末尾元素交换,并缩小堆的范围,重新调整堆结构来实现排序。交换堆顶和末尾元素: 1, 5, 3, 4, 10。交换堆顶和末尾元素: 1, 4, 3, 5, 10。交换堆顶和末尾元素: 1, 3, 4, 5, 10。构建最大堆: 10, 5, 3, 4, 1。调整堆: 5, 4, 3, 1, 10。调整堆: 4, 1, 3, 5, 10。调整堆: 3, 1, 4, 5, 10。

捕风捉你 · 星桥API接入与大模型实战 1451

堆排序详解与代码实现

文章目录一、堆排序基本介绍二、大顶堆和小顶堆2.1 大顶堆2.2 小顶堆三、堆排序基本思想四、堆排序代码实现五、代码运行结果 一、堆排序基本介绍 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,他的最好、最坏、平均时间复杂度均为O(nlogn),它也是不稳定排序 堆是具有以下性质的二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆。注意:没有要求节点的左孩子和右孩子的值的大小关系 每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆 一般升序采用大顶堆,降序采用小顶堆

IronmanJay 1274

堆排序python实现_Python实现堆排序的方法详解

本文实例讲述了Python实现堆排序的方法。分享给大家供大家参考,具体如下:堆排序作是基本排序方法的一种,类似于合并排序而不像插入排序,它的运行时间为O(nlogn),像插入排序而不像合并排序,它是一种原地排序算法,除了输入数组以外只占用常数个元素空间。堆(定义):(二叉)堆数据结构是一个数组对象,可以视为一棵完全二叉树。如果根结点的值大于(小于)其它所有结点,并且它的左右子树也满足这样的性质,那...

weixin_39736913的博客 416

经典排序算法之堆排序详解|c++代码实现|什么是堆排序|如何代码实现堆排序

经典排序算法之堆排序详解|c++代码实现|什么是堆排序|如何代码实现堆排序

qq_64431512的博客 3095
上一篇: =C入门=深入研究 字符串与字符数组
下一篇: C++文件操作
supdriver
博客等级 码龄3年 192粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值