C++数据结构X篇_25_堆排序(不稳定的排序)

news2024/11/17 16:32:46

本篇根据十大经典排序算法-堆排序算法详解进行整理和补充。

文章目录

  • 1. 基础知识点
    • 1.1 完全二叉树
    • 1.2 堆的基础知识
  • 2. 堆排序
    • 2.1 什么是堆排序
    • 2.2 算法原理
      • 2.2.1 理解方法1
      • 2.2.2 理解方法2
    • 2.3 算法实现
  • 3. 堆排序算法特点
    • 3.1 时间复杂度
    • 3.2 空间复杂度
    • 3.3 稳定性

1. 基础知识点

1.1 完全二叉树

之前在介绍二叉树时讲过一个完全二叉树,具体参考C++数据结构X篇_13_二叉树基本概念、性质及表示法,其中介绍到的完全二叉树,下图即为一个完全二叉树。
在这里插入图片描述
在这里插入图片描述

可以看到从A–G是一个满二叉树,最后一层靠左,完全二叉树可以按照从上往下,从左往右将A–J存到数组中,将A–J假设为1-10的数(可以认为是下标),D对应数字4的左子树为24=8,对应的D的右子树为24+1,在A–J数组中去看,D的下标为4,左右子树值为8和9。从上可以看出,完全二叉树可以存储到数组中,同时保持其节点关系。

任意非叶子结点,左子树2i,右子树2i+1.

如果将乱序的数给到完全二叉树中,就变成如下图所示的结构:
在这里插入图片描述

1.2 堆的基础知识

什么是堆呢?
堆的性质:

  • 堆是一颗完全二叉树

  • 堆是一种重要的数据结构,堆分为大根堆和小根堆,大根堆堆顶的数据是最大的,小根堆堆顶的数据是最小的,堆在逻辑结构上是一颗完全二叉树,这棵树中如果满足根节点大于左右子树,每个节点都满足这个条件就是大根堆,反之就是小根堆。(这里的大和小并不是传统意义下的大和小,它是相对于优先级而言的)
    常用操作中,堆的插入就是把新的元素放到堆底,然后检查它是否符合堆的性质,如果符合就丢在那里了,如果不符合,那就和它的父亲交换一下,一直交换交换交换,直到符合堆的性质,那么就插入完成了

  • 父结点比其子结点都大,最大的数在最上面,称为大顶堆

  • 父结点比其子结点都小,最小的数在最上面,称为小顶堆

  • 如果要实现从小到大的升序排序,可以采用大顶堆,相应的,降序排序的话就采用小顶堆

2. 堆排序

2.1 什么是堆排序

堆排序就是永远把最大或最小的数扔在顶上。
堆排序(Heapsort)是利用二叉堆的概念来排序的选择排序算法,分为两种:

  • 升序排序:利用最大堆进行排序
  • 降序排序:利用最小堆进行排序

2.2 算法原理

2.2.1 理解方法1

再对上面已经变为完全二叉树的数据,再将其变为大顶堆
按照大顶堆的概念,父结点比其子结点都大,由于叶子结点没有子树,无法对比,因此只对非叶子结点4、2、8、0调整,进行初始化堆
给了一个数组,可以将其理解为完全二叉树,但还不满足堆的条件,需要初始化堆调整为堆。

  • (1)初始化堆
    第一步:总共9个数,9/2=4,可以发现数组元素的个数除以2,正好是最后一个非叶子结点,从len/2往前遍历完每一个非叶子结点
    找到0,与其左右子树比较调整,具体代码如下:
int index = len/2; //当前调整的结点
//拿到最后一个非叶子结点及左右子树下标

int lchild = index*2; //最后一个非叶子结点的左子树下标
int rchild = index*2+1;//最后一个非叶子结点的右子树下标
int max = index; //最后一个非叶子结点下标

//进行判断
if(arr[lchild] > arr[max])
{
max = lcild;
}
if(arr[rchild] > arr[max])
{
max = rcild;
}
if

完成0位置结点的大顶堆比较交换,遍历完成4、2、8的结点的遍历交换,直至9到堆顶,这也就完成了初始化堆,形成一个基础的堆,如下:
在这里插入图片描述

  • (2)堆的排序调整
    第二步:堆已有的情况下,最大的值就在堆顶,对于数组下标即为0的位置,对于二叉树来说就是1号位置,将9与尾部的0交换(此处需要注意,视频中遗忘了左子树的比较,所以还是左子树数据存在问题,以右子树来理解思路
    在这里插入图片描述

此时的堆顶的0结点不符合大顶堆概念,从该结点开始从上往下调整
在这里插入图片描述

实现头和尾交换一次就调整一次,堆排序就是调整的过程

初始化的时候,从下往上调整,i=len / 2 --为开始调整非叶子结点就变为堆
从上往下调整,结束条件为>=len/2

2.2.2 理解方法2

给定一个最大堆如下图所示,以该最大堆进行演示堆排序
在这里插入图片描述
首先,删除堆顶元素10(即最大的元素),并将最后的元素3补充到堆顶,删除的元素10,放置于原来最后的元素3的位置
在这里插入图片描述
根据二叉堆的自我调整,第二大的元素9会成为二叉堆新的堆顶
在这里插入图片描述
删除元素9,元素8成为最大堆堆顶
在这里插入图片描述
删除元素8,元素7成为最大堆堆顶
在这里插入图片描述
依次删除最大元素,直至所有元素全部删除
在这里插入图片描述
此时,被删除的元素组成了一个从小到大排序的序列
在这里插入图片描述

2.3 算法实现

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

void PrintArray(int arr[],int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

void MySwap(int arr[],int a,int b)
{
	int temp = arr[a];
	arr[a] = arr[b];
	arr[b] = temp;
}

/*
@param myArr 待调整的数组
@param index 待调整的结点的下标
@param len 数组的长度
*/
void HeapAdjust(int arr[], int index, int len)
{
    //先保存当前结点的下标
	int max = index;
	//保存左右孩子的数组下标
	int lchild = index * 2 + 1;
	int rchild = index * 2 + 2;

	if (lchild < len && arr[lchild]>arr[max])
	{
		max = lchild;
	}
	if (rchild < len && arr[rchild]>arr[max])
	{
		max = rchild;
	}

	if (max != index)
	{
		//调整后还有不满足大顶堆的,交换两个节点
		MySwap(arr, max, index);
		HeapAdjust(arr, max, len);
	}
}

//堆排序
void HeapSort(int myArr[], int len)
{
	//初始化堆
	for (int i=len/2-1;i>=0;i--)
	{
		HeapAdjust(myArr, i, len);
	}

	//交换堆顶元素和最后一个元素
	for (int i=len-1;i>=0;i--)
	{
		MySwap(myArr, 0, i);
		//交换之后,需要重新进行调整堆
		HeapAdjust(myArr, 0, i);
	}
}

int main(void)
{
	int myArr [] = {4,2,8,0,5,7,1,3,9};
	int len = sizeof(myArr) / sizeof(int);
	PrintArray(myArr,len);

	//堆排序
	HeapSort(myArr, len);
	PrintArray(myArr, len);

	return 0;
}

运行结果:
在这里插入图片描述

3. 堆排序算法特点

3.1 时间复杂度

下沉调整的时间复杂度等同于堆的高度O(logn),构建二叉堆执行下沉调整次数是n/2,循环删除进行下沉调整次数是n-1,时间复杂度约为O(nlogn)

3.2 空间复杂度

堆排序算法排序过程中需要一个临时变量进行两两交换,所需要的额外空间为1,因此空间复杂度为O(1)

3.3 稳定性

堆排序算法在排序过程中,相同元素的前后顺序有可能发生改变,所以堆排序是一种不稳定排序算法

  1. 视频地址:堆排序思路,堆排序代码

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

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

相关文章

深度学习| U-Net网络

U-Net网络 基础知识和CNN的关系反卷积ReLU激活函数 U-Net入门U-Net网络结构图为什么需要跳跃连接U-Net的输入U-Net的应用 基础知识 理解U-Net网络结构需要相关知识点。 和CNN的关系 U-Net也是CNN&#xff08;Convolutional Neural Network&#xff0c;卷积神经网络&#xff…

网络架构学习1

文章目录 网络架构学习11. 传统CNN卷积神经网络1.1 基本思想1.2 VCG16(经典CNN网络架构之一) 2. 两种经典的网络架构2.1 FCN网络2.2 U-Net网络 3. FCNVMB(基于U-Net架构)3.1 FCNVMB 主要思想3.2 FCNVMB 提供的其他思想 网络架构学习1 1. 传统CNN卷积神经网络 1.1 基本思想 C…

Android SurfaceFlinger做Layer合成时,如何与HAL层进行交互

目录 零、本文讨论问题的范围一、问题&#xff1a;SurfaceFlinger图层合成选择实现方式的两难1.1 从OpenGL ES、HWC本身来讲1.2 以HWC为主导的判断逻辑 二、SurfaceFlinger与HAL层进行交互的具体实现框架2.1 SurfaceFlinger 调用 OpenGL ES 流程2.2 FrameBuffer2.3 SurfaceFlin…

c语言从入门到实战——数组

数组 前言1. 数组的概念2. 一维数组的创建和初始化2.1 数组创建2.2 数组的初始化2.3 数组的类型 3. 一维数组的使用3.1 数组下标3.2 数组元素的打印3.3 数组的输入 4. 一维数组在内存中的存储5. sizeof计算数组元素个数6. 二维数组的创建6.1 二维数组得概念6.2 二维数组的创建 …

Java集成腾讯云OCR身份证识别接口

一、背景 项目用到身份证识别获取人员信息的功能&#xff0c;于是想到了腾讯云提供这样的API。在整合代码过程都很顺利&#xff0c;利用腾讯云官方SDK很快集成进来。但是在上测试环境部署时有了新的问题&#xff0c;通过Nginx代理后的环境无法访问到目标腾讯云接口&#xff0c;…

buuctf_练[CSCCTF 2019 Qual]FlaskLight

[CSCCTF 2019 Qual]FlaskLight 文章目录 [CSCCTF 2019 Qual]FlaskLight掌握知识解题思路关键paylaod 掌握知识 内置函数的过滤&#xff0c;globals变量的过滤&#xff0c;调用内部变量或函数的OS函数进行命令执行 解题思路 打开题目链接&#xff0c;很明显看标题和内容是fla…

【动态基础】从暴力递归到动态规划

C面经汇总 系列综述&#xff1a; 目的&#xff1a;本系列是个人整理为了秋招和实习面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡背诵量与深入程度。 来源&#xff1a;材料主要源于算法大神&#xff08;左程云&#xff09;教你从暴力递归到动态规划进行的&#xf…

vue实现连接线

效果展示 实现代码 下载插件npm install --save leader-line-vue <template><div class"wrap"><div ref"start" class"start">start</div><div ref"end" class"end">end</div></d…

数据结构时间复杂度(补充)和空间复杂度

Hello&#xff0c;今天事10月27日&#xff0c;距离刚开始写博客已经过去挺久了&#xff0c;我也不知道是什么让我坚持这么久&#xff0c;但是学校的课真的很多&#xff0c;很少有时间多出来再学习&#xff0c;有些科目马上要考试了&#xff0c;我还不知道我呢不能过哈哈哈&…

Django 全局配置 settings 详解

文章目录 1 概述1.1 Django 目录结构 2 常用配置&#xff1a;settings.py2.1 注册 APP&#xff1a;INSTALLED_APPS2.2 模板路径&#xff1a;TEMPLATES2.3 静态文件&#xff1a;STATICFILES_DIRS2.4 数据库&#xff1a;DATABASES2.5 允许访问的主机&#xff1a;ALLOWED_HOSTS 1 …

[SQL开发笔记]UPDATE 语句:更新表中的记录

一、功能描述&#xff1a; UPDATE 语句&#xff1a;用于更新表中的记录 二、UPDATE 语句语法详解&#xff1a; UPDATE 语法 UPDATE table_nameSET column1value1,column2value2,...WHERE some_columnsome_value; 参数说明&#xff1a; 1.table_name&#xff1a;要修改的表…

【Docker】github Actions自动构建

通过github的Actions 实现代码push仓库后自动构建容器并发布到DockerHub. 创建项目 首先我们创建一个项目,这里我就用Vue项目进行演示. npm init vuelatest Actions-demo-swback进去项目&#xff0c;按照提示执行 npm install npm run dev 启动项目. 首先保证项目的正常启动…

DAY36 738.单调递增的数字 + 968.监控二叉树

738.单调递增的数字 题目要求&#xff1a;给定一个非负整数 N&#xff0c;找出小于或等于 N 的最大的整数&#xff0c;同时这个整数需要满足其各个位数上的数字是单调递增。 &#xff08;当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单…

Python机器学习基础(一)---数据集加载的方法

几个数据集加载的方式 鸢尾花练习资源(这个资源有瑕疵&#xff0c;index列和Species 都是带”“的字符串 导致一些加载现实问题&#xff0c;从而验证 还是pandas最好用) "index","Sepal.Length","Sepal.Width","Petal.Length","…

echarts中横向柱状图的数字在条纹上方

实现效果&#xff1a; 数字在条纹的上方 实现方法&#xff1a;这些数字是用新添加一个坐标轴来实现的 直接添加坐标轴数字显示是在条纹的正右边 所以需要配置一下偏移 完整代码 var option {grid: {left: "3%",right: "4%",bottom: "3%",cont…

FreeROTS 任务通知和实操 详解

目录 什么是任务通知&#xff1f; 任务通知值的更新方式 任务通知的优势和劣势 任务通知的优势 任务通知的劣势 任务通知相关 API 函数 1. 发送通知 2. 等待通知 任务通知实操 1. 模拟二值信号量 2. 模拟计数型信号量 3. 模拟事件标志组 4. 模拟消息邮箱 什么是任务…

高防CDN:网络攻防的坚强防线

在当今数字化时代&#xff0c;网络攻击已经成为一种常态&#xff0c;对企业和个人的网络资产构成了严重威胁。为了应对这些风险&#xff0c;高防CDN&#xff08;Content Delivery Network&#xff09;已经崭露头角&#xff0c;它不仅提供内容分发&#xff0c;还整合了强大的网络…

电脑上使用的备忘记事软件哪一款好用点?

生活中充斥着大大小小的任务&#xff0c;如工作方面、学习方面、生活方面等&#xff0c;多种事务掺杂交错在一起非常容易忘记&#xff0c;为避免忘记重要的事情&#xff0c;大家可以借助电脑上好用的备忘录工具来进行记事。 支持在电脑上使用的备忘录软件是比较多的&#xff0…

论文阅读 - Learning Human Interactions with the Influence Model

NIPS01 早期模型 要求知识背景&#xff1a; 似然函数&#xff0c;极大似然估计、HMM、期望最大化 目录 1 Introduction 2 The Facilitator Room 3 T h e I n f l u e n c e M o d e l 3 . 1 ( R e ) i n t r o d u c i n g t h e I n f l u e n c e M o d e l 3 . 2 L e…

SpringCloud Alibaba【三】Gateway

Gateway配置与使用 前言新建gateway子项目pom.xml配置文件启动类访问接口方式 测试拓展 前言 在工作中遇到一种情况&#xff0c;一个父项目中有两个子项目。实际使用时&#xff0c;需要外网可以访问&#xff0c;宝信软件只能将一个端口号发布在外网上&#xff0c;所以需要运用…