【排序算法】堆排序(Heapsort)

news2024/11/20 18:40:29

✨✨✨专栏:排序算法 

          🧑‍🎓个人主页:SWsunlight

目录

​编辑

前言:

一、堆排序:

时间复杂度:

空间复杂度:

算法稳定性:

二、升序的实现:通过建大堆实现

>思路:

1、向上调整算法实现大堆的建立:了解即可

 2、向下调整算法实现大堆的建立:

 3、排序:

 代码实现升序:

三、降序的实现:通过建小堆实现

>思路:

1、向上调整算法实现小堆的建立:了解即可

​编辑

2、向下调整算法实现小堆的建立:

​编辑

3、排序:

代码:

四、建堆的时间复杂度计算:

五、总结:



前言:

        本文基于对堆已经理解并通过代码实现后进行的,不知道堆的可以看上篇文章:堆

一、堆排序:

概念:   堆排序(Heapsort)是指利用 堆 这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆

利用了堆的特点:堆分为大根堆和小根堆,是完全二叉树。为啥升序大堆,降序小堆:大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。相反小堆最小值一定在堆顶;

时间复杂度:

        堆排序包括构建堆排序两个操作:
        构建堆的时间复杂度:              T(n) = O(n)
        排序过程的时间复杂度:         ​​​​  T(n) = O(nlog2n)
        堆排序整体的时间复杂度:       T(n) = O(nlog2n)

空间复杂度:

         O(1)     实现排序不需要额外的空间,就是以数组自身的空间进行的

算法稳定性:

           堆的调整过程中,值相同的结点在比较过程中不能保证顺序,所以堆排序是一种不稳定的排序方法

二、升序的实现:通过建大堆实现

>思路:

  1. 将待排序数组构造成一个大堆
  2. 这个序列最大值在堆顶
  3. 将其与末尾元素进行交换,末尾变成最大值
  4. 将剩下的n-1个结点重新调整为大堆
  5. 再次将最大值与新的末尾元素(此时有n-1个结点)交换
  6. 重复下去,到最后就是有序的了,整个数组最小的元素此时在栈顶

1、向上调整算法实现大堆的建立:了解即可

我们将上图数组的第一个元素作为堆顶(即下标为0的元素),进行建堆,然后将第二个数据看成是插入堆(会进行比较,谁大谁会放到堆顶),依次类推,直到数组的最后一个元素,就是模拟的大堆进行插入操作,只是这些值已经有了,相当于插好了,只是需要进行调整

如下是我们将数组在逻辑结构上画成堆的样子,但不是堆,不满足堆的性质,所以需要我们进行调整算法

看下面:从第二层开始进行调整,根据下标来进行的,依次类推,会一直调整到最后一个元素

 流程图:手绘的 红色箭头表示所在下标(位置) 黑色就是结束一次向上调整函数

堆也就建立如下图:是大堆,但是不是有序的,让他变成有序,等会将考虑,一口吃不成胖子

 向上调整的算法:

下标为0开始的

 2、向下调整算法实现大堆的建立:

堆的删除就是使用的向下调整算法,我们会发现删除的前提是它是,那么若是将数组的首元素直接向下调整是不行的因为此时这个数组逻辑上看它就不是堆,若是左子树、右子树是大堆,那么我就可以直接向下调整;

我们想办法将左右子树变成大堆;是不是可以逆向思维呢?叶子节点是不可以向下调整的,那我找到叶子结点的父节点,是不是就可以进行调整,一点一点从数组的最后一个元素开始,但是看图我们会发现实际是从第一个非子叶结点开始的 上图变左、右子树,最后到了根结点,让根结点向下调整,就完成了大堆的建立

如下图流程:

向下调整的算法: 

叶子结点的父亲开始传,这个不就是通过孩子节点求父亲的公式么;开始传

 3、排序:

简单多了类似堆的删除(假删除并不是真的删除o);是将根结点先与最后一个结点互换,然后将

元素个数n-1  将新的元素个数传上去进行向下调整

 因为堆顶元素在这个堆中用远是最大的,所以不断的将堆顶元素和堆的最后一个元素进行交换,直到将这个大堆变成只剩下根结点的堆,此时数据变成有序了

这个过程我的堆的元素个数在不断减小

 代码实现升序:

typedef int HpDataType;
//交换数据
void Swp(HpDataType* p1, HpDataType* p2)
{
	assert(p1 && p2);
	HpDataType tmp = *p2;
	*p2 = *p1;
	*p1 = tmp;
}

//大堆:向上调整,child 为孩子
void AdjustUpBig(HpDataType* a, int child)
{
	assert(a);
	//parent 父亲结点
	int  parent = (child - 1) / 2;
	//循环的进行从3个方面考虑:
	// 1、初始条件
	// 2、中间过程
	// 3、结束条件
	//循环有2种写法:
	while (child > 0 && a[child] > a[parent])
	{
		//互换;
		Swp(&a[child], &a[parent]);
		child = parent;
		parent = (child - 1) / 2;
	}
	
}
//大堆:向下调整  //数组  元素个数  parent 父亲节点
void AdjustDownBig(HpDataType* a, int n, int parent)
{
	assert(a);
	//用到假设法:我们要保证我的父亲节点比最大的儿子节点大或者相等;假设左孩子大
	int child = 2 * parent + 1;
	while (child < n)
	{//判断一下,完全二叉树,有可能会有有孩子不存在的情况
		if (a[child] < a[child + 1] && child + 1 < n)
		{
			//拿孩子大的去和父亲比较
			child = child + 1;
		}
		if (a[child] > a[parent])
		{
			Swp(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}

	}

}

//打印
void Prin(int* a, int n)
{
	int i;
	for (i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}

//大堆:变量含义:数组  元素个数
//大堆:向上调整实现升序
void HpBig(int* a, int n)
{
	int i;
	//从第二层的第一孩子开始向上调整建堆
	for (i = 1; i < n; i++)
	{
		AdjustUpBig(a, i);
	}
	int k = n;
	//排序
	for (i = n - 1; i > 0; i--)
	{
		Swp(&a[0], &a[i]);
		k--;
		AdjustDownBig(a, k, 0);
	}
	//打印
	Prin(a, n);
}
//大堆:向下调整实现升序
void HpBig2(int* a, int n)
{
	int i;	
	//向下调整建堆
	for(i = (n - 1-1); i >=0; i--)
	{
		AdjustDownBig(a, n, i);
	}
	int k = n;
	//排序
	for (i = n - 1; i > 0; i--)
	{
		Swp(&a[0], &a[i]);
		k--;
		AdjustDownBig(a, k, 0);
	}
	//打印
	Prin(a, n); 

}

三、降序的实现:通过建小堆实现

>思路:

  1. 将待排序数组构造成一个小堆
  2. 这个序列最小值在堆顶
  3. 将其与末尾元素进行交换,末尾变成最小值
  4. 将剩下的n-1个结点重新调整为小堆
  5. 再次将最小值与此时(为n-1个结点的小堆)的末尾元素交换
  6. 重复下去,到最后就是有序的了,整个数组最大的元素此时在栈顶

1、向上调整算法实现小堆的建立:了解即可

思路一样的,流程图都是大差不差的,无非就是变成了孩子小于爹就交换

2、向下调整算法实现小堆的建立:

3、排序:

都是大堆实现过的,思路就是一样的,就是要注意性质,决定了符号(大于还是小于)

代码:

//因为是直接复制过来的,所以用来Typedef改名
typedef int HpDataType;
//交换数据
void Swp(HpDataType* p1, HpDataType* p2)
{
	assert(p1 && p2);
	HpDataType tmp = *p2;
	*p2 = *p1;
	*p1 = tmp;
}
//打印
void Prin(int* a, int n)
{
	int i;
	for (i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}
//小堆:向上调整完成降序
void HpSmall(int* a, int n)
{
	int i;
	//从第二层开始调整
	for (i = 1; i < n; i++)
	{
		AdjustUpSmall(a, i);
	}
	int k = n;
	//排序:
	for (i = (n - 1-1); i > 0; i--)
	{
		Swp(&a[0], &a[i]);
		k--;
		AdjustDownSmall(a, k, 0);
	}
	//打印
	Prin(a, n);


}
//小堆:向下调整实现降序
void HpSmall2(int* a, int n)
{
	int i;
	
	//建堆
	for(i = n - 1; i >=0; i--)
	{
		AdjustDownSmall(a, n, i);
	}
	int k = n;
	//排序:
	for (i = n - 1; i > 0; i--)
	{
		Swp(&a[0], &a[i]);
		k--;
		AdjustDownSmall(a, k, 0);
	}
	//打印
	Prin(a, n);
}

四、建堆的时间复杂度计算:

向下调整算法的时间复杂度

时间复杂度为O(N)


向上调整算法的时间复杂度:

计算过程和上面雷同

时间复杂度:O(N*logN)

我们发现这2个不同的特点是:

向下调整:结点数量越多,调整次数越少;(反比)

向上调整:结点数量越多,调整次数越多;(正比)


五、总结:

        对于堆排序的实现,其实只要彻底掌握了堆的实现即可完成,对于向上向下调整算法有了理解,其实堆排序的实现也就不难了,原理都是一样的,非常类似,有了大堆实现升序的思路,降序也就一起出来了,画图更有助于理解。本文图不是很好看,还在努力提升画图技术!!注意的是向上和向下调整建堆的时间复杂度是不一样的,向下调整对于堆排序是最好的选择

  完                  结                           撒                花

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

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

相关文章

《Effective Objective-C 2.0》读书笔记——接口与API设计

目录 第三章&#xff1a;接口与API设计第15条&#xff1a;用前缀避免命名空间冲突第16条&#xff1a;提供“全能初始化方法”第17条&#xff1a;实现description方法第18条&#xff1a;尽量使用不可变对象第19条&#xff1a;使用清晰而协调的命名方式第20条&#xff1a;为私有方…

中国真人认证的相亲交友恋爱平台有哪些?测评5款高质量婚恋脱单软件

不少朋友都表示自己的社交圈子过于狭窄&#xff0c;朋友也没几个&#xff0c;那今天就来聊聊我是通过何种平台找到对象的。我与男朋友是在网络上相识的&#xff0c;许多朋友同样也是通过网络来相亲。不过我们的成功&#xff0c;真的真的不能表明网络上全都是好人&#xff0c;各…

你不知道的C语言知识(第2期)

本期介绍&#x1f356; 主要介绍&#xff1a;C语言中一些大家熟知知识点中的盲区&#xff0c;这是第二期。 文章目录 1. 一维数组在内存中的存储方式2. sizeof计算数组元素的个数3. 二维数组3.1 概念3.2 二维数组在内存中的存储3.3 初始化省略行&#xff0c;但不能省略列 4. 变…

【Python】 去除字符串中的所有空白字符

基本原理 在Python中&#xff0c;字符串&#xff08;String&#xff09;是不可变的数据类型&#xff0c;这意味着一旦创建了一个字符串&#xff0c;就不能修改它的内容。然而&#xff0c;我们可以创建一个新的字符串&#xff0c;它包含原始字符串中的字符&#xff0c;但不包含…

入门四认识HTML

一、HTML介绍 1、Web前端三大核心技术 HTML&#xff1a;负责网页的架构 CSS&#xff1a;负责网页的样式、美化 JS&#xff1a;负责网页的行动 2、什么是HTML HTML是用来描述网页的一种语言。 3、Html标签 单标签<html> 双标签<h>内容</h> 4、标…

Visual Studio 下的Qt工程无法打开 “xxx.ui“ 文件和LNK1104 无法打开文件“Qt5Cored.lib”错误

一、问题&#xff1a; VS下Qt环境准备好后&#xff0c;创建了Qt工程然后点击 Form Files 下的 “xxx.ui” 文件&#xff0c;在弹出 Qt 设计师 界面后闪退并显示如下错误&#xff1a; 二、解决 1、工具栏处依次点击&#xff1a;扩展 一> Qt VS Tools 一> options 弹出选…

在windows下dat文件转mat

环境配置 需要安装hdf5库&#xff0c;参考https://blog.csdn.net/qq_36314864/article/details/139168631 代码下载 https://download.csdn.net/download/qq_36314864/89349060 为了支持大文件的.dat文件转换&#xff0c;我们需要考虑如何处理大量数据以避免内存不足的问题…

利用kubeadm安装k8s集群 以及跟harbor私有仓库下载镜像

目录 环境准备 master&#xff08;2C/4G&#xff09; 192.168.88.3 docker、kubeadm、kubelet、kubectl、flannel node01&#xff08;2C/2G&#xff09; 192.168.88.4 docker、kubeadm、kubelet、kubectl、flannel node02&#xff08;…

docker 安装 yapi

文章目录 docker 安装 yapi一、拉取镜像二、创建目录三、添加配置文件四、初始化数据库表五、启动 yapi六、测试以及修改默认密码 没有 MongDB 的可以先看这个教程&#xff1a;MongDB安装教程 docker 安装 yapi 版本&#xff1a; 1.9.5 一、拉取镜像 docker pull yapipro/y…

ClickHouse课件

列式存储数据库&#xff1a;hbase clickhouse 简介 ClickHouse入门 ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库&#xff08;DBMS&#xff09;&#xff0c;使用C语言编写&#xff0c;主要用于在线分析处理查询&#xff08;OLAP&#xff09;&#xff0c;能够使用…

Python中文分词工具库之jieba使用详解

概要 在自然语言处理(NLP)领域,中文文本的分词是一个重要且基础的任务。Python的jieba库是一个广泛使用的中文分词工具,提供了丰富的功能,包括精准模式、全模式、搜索引擎模式等,适用于不同的应用场景。本文将详细介绍jieba库,包括其安装方法、主要特性、基本和高级功能…

Spark累加器

1. 累加器 累加器&#xff1a;分布式共享只写变量 考虑如下计算RDD中数据的和&#xff1a; val rdd sc.makeRDD(List(1, 2, 3, 4))var sum 0 rdd.foreach(num > {sum num} )println("sum " sum) 预期结果10&#xff0c;但其实不是 foreach里面的函数是在…

rtemis 包:多种机器学习算法集成!兼顾数据处理与可视化美图

rtemis 是一个集机器学习与可视化于一体的 R 包&#xff0c;用于各种高级机器学习研究和应用。整体而言&#xff0c;该软件有三个目标&#xff1a; 「应用数据科学」&#xff1a;使高级数据分析高效且易于使用 「机器学习研究」&#xff1a;提供一个平台以开发和测试新颖的机器…

添加、修改和删除列表元素

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 添加、修改和删除列表元素也称为更新列表。在实际开发时&#xff0c;经常需要对列表进行更新。下面我们介绍如何实现列表元素的添加、修改和删除。 …

深度学习之使用Matlab乳腺癌分类检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 乳腺癌作为女性最常见的恶性肿瘤之一&#xff0c;对女性的健康构成了严重威胁。乳腺癌的早期发…

基于51单片机的音乐喷泉

基于51单片机的音乐喷泉 &#xff08;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.检测音乐信号的声音强度&#xff0c;使喷头的水柱能够根据音乐的节奏和音量起伏&#xff1b; 2.系统将声音强度转化为模拟信…

神经网络的工程基础(三)——更优化的最优化算法

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 本文将讨论更优化的最优化问题算法。 关于大语言模型的内容&#xff0c;推荐参考这个专栏。 内容大纲 相关说明一、概述二、算…

【你眼中的IT行业现状与未来趋势展望】

随着技术的不断进步&#xff0c;IT行业已成为推动全球经济和社会发展的关键力量。从云计算、大数据、人工智能到物联网、5G通信和区块链&#xff0c;这些技术正在重塑我们的生活和工作方式。你眼中IT行业的现状及未来发展趋势是怎么样的&#xff1f;无论您是行业领袖、技术专家…

K8S中Prometheus+Grafana监控

1.介绍 phometheus:当前一套非常流行的开源监控和报警系统。 运行原理&#xff1a;通过HTTP协议周期性抓取被监控组件的状态。输出被监控组件信息的HTTP接口称为exporter。 常用组件大部分都有exporter可以直接使用&#xff0c;比如haproxy,nginx&#xff0c;Mysql,Linux系统信…

论文精读:UFO: A UI-Focused Agent for Windows OS Interaction

UFO : A UI-Focused Agent for Windows OS Interaction Status: Reading Author: Bo Qiao, Chaoyun Zhang, Dongmei Zhang, Liqun Li, Minghua Ma, Qinglong Zhang, Qingwei Lin, Saravan Rajmohan, Shilin He, Si Qin, Xiangyu Zhang, Yu Kang Institution: 微软&#xff08;…