堆排序的实现原理

news2025/2/8 18:06:12

一、什么是堆排序?

        堆排序就是将待排序元素以一种特定树的结构组合在一起,这种结构被称为堆。

        堆又分为大根堆和小根堆,所谓大根堆即为所有的父节点均大于子节点,但兄弟节点之间却没有什么严格的限制,小根堆恰恰相反,是所有的根节点均小于子节点。

        所以为了能够实现堆排序,第一个步骤就是将待排序的元素建成堆的形式,其次就是将建好的大根堆(小根堆)与堆的最后一个元素交换,然后再对新的堆进行向下的调整,但是在调整过程中,所有经过交换过的堆底元素不再进行新的调整,直到将倒数第二个元素调整完毕后结束。

        所以说堆排序虽说效率较高,但是它的算法步骤却不如其他排序那么明了,需要将它的每一个算法步骤了解清楚后,才能清晰的解析出来。

二、堆排序的算法步骤

        在排序家族中,堆排序是一种效率比较高的方法,它的 时间复杂度为O(nlogn),空间复杂度为O(1),它的主要排序步骤为:建堆、交换堆顶、堆底元素再向下调整。

        但是在此之前,我们需要先解析出两个分支算法,分别是向下调整和向上调整。

        顾名思义,向上(下)调整分别是从堆底(顶)为起始向堆顶(底)进行调整,目的则是严格维护堆的结构不被破坏。

        在本文的演示中,我们暂且以大根堆为例。

2.1向下调整

        首先,我们以【2,6,3,0,7】为例进行演示。

        我们先按照顺序构建堆,如下所示:

        然后我们建立两个int类型的变量parent和child,分别指向2和它的子节点,这里子节点的公式为(parent*2+1)。

        接下来就是要将parent所指的元素和child所指的元素进行比较,如果parent所指元素小于child所指元素则进行交换,再更新两个变量的位置,如果child所指元素不大于parent所指元素,则跳出循环。

                这样,一趟的向下调整就完成了,下面我们用代码实现:

//向下调整
void Modify_down(int parent , int end)
{
	int child = parent * 2 + 1;
	while (child <= end)
	{
		if (child + 1 < end && _v[child] < _v[child + 1])
		{
			child++;
		}
		if (_v[child] > _v[parent])
		{
			swap(_v[parent], _v[child]);
			parent = child;
			child = child * 2 + 1;
		}
		else
			break;
	}
}

2.2向上调整

        向上调整和向下调整有所不同,需要先找出其孩子节点中最大的那个,比较之后再进行交换操作,以【2,6,7,0,3】为例。

        调整过程中,计算父节点的计算方法为【(child-1)/2】,然后比较兄弟节点,找出最大的那个,如果孩子节点大于父节点,就进行交换,然后更换parent和child的下标位置,如果子节点小于父节点就跳出循环。代码如下:

//向上调整
void Modify_up(int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (_v[child] > _v[parent])
		{
			swap(_v[parent], _v[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}

2.3堆排序

        完成两个核心的算法后,我们最后只需将堆排序归纳一下即可。

1、建堆,将堆调整至合法。

//向上调整
void Modify_up(int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (_v[child] > _v[parent])
		{
			swap(_v[parent], _v[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}
//建堆
for (int i = 1; i < _v.size(); i++)
{
	Modify_up(i);
}

2、交换堆顶和堆底元素,然后再进行向下调整堆,在这里对于堆底的下标我们以变量“end”来控制,当end<=0时,则跳出循环。

//向下调整
void Modify_down(int parent , int end)
{
	int child = parent * 2 + 1;
	while (child <= end)
	{
		if (child + 1 < end && _v[child] < _v[child + 1])
		{
			child++;
		}
		if (_v[child] > _v[parent])
		{
			swap(_v[parent], _v[child]);
			parent = child;
			child = child * 2 + 1;
		}
		else
			break;
	}
}

int end = _v.size() - 1;
while (end > 0)
{
	swap(_v[0], _v[end]);
	end--;
	Modify_down(0, end);
}

三、堆排序完整代码

class heapsort
{
public:
	heapsort(vector<int>& v)
		:_v(v)
	{}
	void heap_sort()
	{
		for (int i = 1; i < _v.size(); i++)
		{
			Modify_up(i);
		}
		int end = _v.size() - 1;
		while (end > 0)
		{
			swap(_v[0], _v[end]);
			end--;
			Modify_down(0, end);
		}
	}

	void Print()
	{
		for (int i = 0; i < _v.size(); i++)
		{
			cout << _v[i] << " ";
		}
	}
protected:
	//向上调整
	void Modify_up(int child)
	{
		int parent = (child - 1) / 2;
		while (child > 0)
		{
			if (_v[child] > _v[parent])
			{
				swap(_v[parent], _v[child]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
				break;
		}
	}

	//向下调整
	void Modify_down(int parent , int end)
	{
		int child = parent * 2 + 1;
		while (child <= end)
		{
			if (child + 1 < end && _v[child] < _v[child + 1])
			{
				child++;
			}
			if (_v[child] > _v[parent])
			{
				swap(_v[parent], _v[child]);
				parent = child;
				child = child * 2 + 1;
			}
			else
				break;
		}
	}
private:
	vector<int> _v;
};

四、、堆排序的适用场景

        堆排序适用于关键字较多的情况,如:在几亿个关键字中找出前十个最大的数据,我们只需建立小根堆,然后依次循环十次就能得到想要的数据了。

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

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

相关文章

百度ai人脸识别项目C#

一、项目描述 本项目通过集成百度AI人脸识别API&#xff0c;实现了人脸检测和识别功能。用户可以上传图片&#xff0c;系统将自动识别人脸并返回识别结果。 二、开发环境 Visual Studio 2019或更高版本.NET Framework 4.7.2或更高版本AForge.NET库百度AI平台人脸识别API 三、…

09--keepalived高可用集群

前言&#xff1a;高可用集群配置是大型网站的一个基础&#xff0c;网站可用性的基础保障之一&#xff0c;这里将对应的概念知识和实操步骤进行整理与收集。 1、基础概念详解 1.1、高可用集群 高可用集群&#xff08;High Availability Cluster&#xff0c;简称HA Cluster&am…

已解决java.security.acl.AclNotFoundException异常的正确解决方法,亲测有效!!!

已解决java.security.acl.AclNotFoundException异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 出现问题的场景 报错原因 解决思路 解决方法 分析错误日志 检查ACL文件路径和名称 确认系统权限 修改代码逻辑 确保ACL文…

什么是微分和导数?

文章目录 设立问题微分特性指数特性线性特性常数特性 多项式微分导数 在机器学习领域&#xff0c;有多种解决最优化问题的方法&#xff0c;其中之一就是使用微分。 通过微分&#xff0c;可以得知函数在某个点的斜率&#xff0c;也可以了解函数在瞬间的变化。 设立问题 请想象一…

C++/Qt 小知识记录7

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识7 编译FFMPEG遇到的问题CMakeLists.txt配置FFMPEG的依赖方式&#xff1a; x264在Windows下编译生成*.libVS编译Qt工程时&#xff0c;遇到提示Change Qt Version的情况在QtOsg的窗口上嵌入子窗口&…

Map集合之HashMap细说

最近在看面试题&#xff0c;看到了hashmap相关的知识&#xff0c;面试中问的也挺多的&#xff0c;然后我这里记录下来&#xff0c;供大家学习。 Hashmap为什么线程不安全 jdk 1.7中&#xff0c;在扩容的时候因为使用头插法导致链表需要倒转&#xff0c;从而可能出现循环链表问…

图像分割(四)---(图像显示、灰度直方图和三维灰度图综合分析选取最佳分割方法)

一、引言 对彩色图像进行分割的一种常用方法&#xff0c;是先把彩色图像转灰度图像&#xff0c;然后再选择合适的阈值进行二值分割。但有时彩色图像转灰度图像后不具有典型的双峰特性&#xff0c;二值分割效果不好。本文章提出一种确定彩色图像分割方法的新思路。首先读入一幅彩…

2024山东大学软件学院创新项目实训(9)使用OpenCompass进行模型评估

下载好OpenCompassData-core-20231110.zip 之后&#xff0c;解压压缩包 unzip OpenCompassData-core-20231110.zip 运行代码&#xff1a; python run.py --datasets ceval_gen --hf-path /hy-tmp/7B21/merged --tokenizer-path /hy-tmp/7B21/merged --tokenizer-kwargs p…

【数据结构】线性表之《栈》超详细实现

栈 一.栈的概念及结构二.顺序栈与链栈1.顺序栈2.链栈1.单链表栈2.双链表栈 三.顺序栈的实现1.栈的初始化2.检查栈的容量3.入栈4.出栈5.获取栈顶元素6.栈的大小7.栈的判空8.栈的清空9.栈的销毁 四.模块化源代码1.Stack.h2.Stack.c3.test.c 一.栈的概念及结构 栈&#xff1a;一种…

WDG开门狗

WDG开门狗简介 独立看门狗&#xff0c;它的特点就是独立运行&#xff0c;对时间精度要求较低。独立运行就是独立看门狗的时钟是专用的&#xff0c;LSI内部低速时钟&#xff0c;即使主时钟出现问题了&#xff0c;看门狗也能正常工作&#xff0c;这也是独立看门狗独立的得名原因&…

【34W字CISSP备考笔记】域1:安全与风险管理

1.1 理解、坚持和弘扬职业道德 1.1.1.(ISC)职业道德规范 1、行为得体、诚实、公正、负责、守法。 2、为委托人提供尽职、合格的服务。 3、促进和保护职业。 4、保护社会、公益、必需的公信和自信&#xff0c;保护基础设施。 1.1.2.组织道德规范 1、RFC 1087 &#xff0…

本科生大厂算法岗实习经验复盘:从投递到面试的底层思维!

目录 投递渠道boss直聘官网邮箱内推 面试准备leetcode八股深挖项目自我介绍mock面试技巧答不出来怎么办coding反问 复盘技术交流群用通俗易懂方式讲解系列 节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面…

实战电商大数据项目搭建||电商大数据采集||电商API接口

我会提供给你大概1亿条真实的互联网用户上网数据&#xff0c;至于来源&#xff0c;我先不告诉你&#xff0c;绝对是你在网络上无法找到的宝贵数据源。 此外&#xff0c;还会给你提供一个基于当前数据特点而设计的大数据处理方案。 当然&#xff0c;为了防止用户的隐私部分被泄露…

【已解决】SpringBoot图片更新需重启服务器才能显示

问题描述 1、更新头像&#xff0c;并跳转回列表页&#xff0c;发现显示不出来 2、但是前端获取用户头像的信息是在加载页面就会被调用的&#xff0c;同时前端也不存在所谓的缓存问题&#xff0c;因为没有动这部分代码。 但查看响应是能获得正确的信息&#xff08;前端打印图片…

GitHub Copilot 登录账号激活,已经在IntellJ IDEA使用

GitHub Copilot 想必大家都是熟悉的&#xff0c;一款AI代码辅助神器&#xff0c;相信对编程界的诸位并不陌生。 今日特此分享一项便捷的工具&#xff0c;助您轻松激活GitHub Copilot&#xff0c;尽享智能编码之便利&#xff01; GitHub Copilot 是由 GitHub 和 OpenAI 共同开…

2024年安全员-A证证考试题库及安全员-A证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年安全员-A证证考试题库及安全员-A证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机出的…

合并有序链表

合并有序链表 图解代码如下 图解 虽然很复杂&#xff0c;但能够很好的理解怎么使用链表&#xff0c;以及对链表的指针类理解 代码如下 Node* merge_list_two_pointer(List& list1, List& list2) {Node* new_head1 list1.head;Node* new_head2 list2.head;Node* s…

FFmpeg编译4(1)

ffmpeg.cffmpeg.h 修改ffmpeg文件 修改刚刚拷贝的ffmpeg.c文件&#xff0c;找到int main(int argc, char **argv)函数&#xff0c;将其替换为int run(int argc, char **argv)在修改后的run(int argc, char **argv) 末尾&#xff08;retrun 之前&#xff09;加上如上如下代码&…

跟TED演讲学英文:How language shapes the way we think by Lera Boroditsky

How language shapes the way we think Link: https://www.ted.com/talks/lera_boroditsky_how_language_shapes_the_way_we_think? Speaker: Lera Boroditsky Date: November 2017 文章目录 How language shapes the way we thinkIntroductionVocabularySummaryTranscriptA…

【完全复现】基于改进粒子群算法的微电网多目标优化调度(含matlab代码)

目录 主要内容 部分代码 结果一览 下载链接 主要内容 程序完全复现文献模型《基于改进粒子群算法的微电网多目标优化调度》&#xff0c;以微电网系统运行成本和环境保护成本为目标函数&#xff0c;建立了并网方式下的微网多目标优化调度模型&#xff0c;通过改进…