(手撕)数据结构--->堆

news2024/11/25 1:02:48

文章内容

   

目录

        一:堆的相关概念与结构

        二:堆的代码实现与重要接口代码讲解


让我们一起来学习:一种特殊的数据结构吧!!!!

        一:堆的相关概念与结构

                在前面我们已经简单的学习过了二叉树的链式存储结构了,那么二叉树的顺序存储结构是啥呢?其实二叉树的顺序存储结构我们一般将他叫做

                二叉树为啥有两种形式的存储结构呢?因为堆是一种特殊的二叉树,它特殊的地方在于它的逻辑结构实际上是一颗完全二叉树,在物理结构上我们一般用数组来表示堆的结构,而如果不是完全二叉树我们一般不会用数组成为二叉树的结构,因为假如不是完全二叉树那么我们数组可能会浪费大量的空间。

        用数组作为二叉树的结构的时候我们必须要知道的双亲结点与子节点的下标关系为:

        leftchild=parent*2+1;

        rightchild=parent*2+2;

        parent=(child-1)/2;(child可以是左孩子也可以是右孩子)

        如图:完全二叉树与非完全二叉树在使用顺序存储结构的区别:

                

        在这里就能看出当结构不同时,我们需要采取不同的形式进行表示。

          总结:堆在逻辑结构上是一棵完全二叉树,在物理结构上是一个数组。对于非完全二叉树我们不适用数组的结构表示二叉树。

        


       堆的两种形式(判断数组是不是堆的方式)

        大堆:树中所有的父亲结点都大于或等于孩子结点,且根节点的值是堆中最大的数据。

        小堆:树中所有的父亲结点都小于或等于孩子结点,且根节点的值是堆中最小的数据。

        这也引出了堆的特点:1:堆中某个结点的值总是不大于或不小于父亲结点的值。

                                             2:堆总是一棵完全二叉树。

                                                        


        二:堆的代码实现与接口的讲解

        由于堆所具有的特点我们定义堆的结构为一个数组,与我们的顺序表,栈的结构类似。

        代码:


typedef int HeapDataType;

typedef struct Heap
{
	HeapDataType* a;
	int Size;
	int Capacity;
}HP;

        接下来就是我们熟悉的接口了,一些不难理解的接口我就直接跳过,对其它类型的接口进行讲解。

        初始化堆:其实这个接口有两种初始化的代码:1:就是不开辟空间,等我们实际插入数据的时候来考虑增容和开辟空间。2:是传入一个数组然后将这个数组里面的值拷贝到我们需要开辟的空间当中。

        代码如下:

        

void InitHeap(HP* php)
{
	assert(php);
	php->a = NULL;
	php->Size = php->Capacity = 0;
}

       堆的销毁:直接销毁我们动态开辟的空间。

        代码如下:

void DestoryHeap(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->Capacity = php->Size = 0;
}

        接下来我们先讲两个重要的关于堆的算法向上调整算法与向下调整算法

        首先这两个算法的时间复杂度都是log(N)

        这两个算法在建堆的时候作用很大

        我们先讲解

        向上调整算法

                 前提:我们所插入的值前面的结构必须是堆

                接下来我们通过图的方式来讲解这个算法的工作原理

                        

        代码实现:

        

void AdjustUp(HeapDataType* 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;
		}
	}
}

        总结算法思想:以建大堆为列,将插入的值与双亲进行比较,如果插入的值大于它的双亲的值,那么就交换孩子与双亲,可能我们插入的值非常大,那么可能会到达根节点所以我们使用循环来进行完成,最坏的情况就是我们要向上调整高度次,而完全二叉树的高度我们之前也算过,所以时间复杂度为:log(N);

        向下调整算法 

                   使用前提:左右子树都是堆

               简单图解向下调整算法:

                 

                代码如下:

                

void AdjustDown(HeapDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//找小的那个孩子
		if (child+1<n && a[child] >a[child + 1] )
		{
			child++;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

        代码是按小堆而写的        

        注意:这里我们需要考虑到一种特殊的情况,就是当我们孩子结点为最后一个结点的时候那么我们对下标为child+1的结点访问时会越界,而且我们在判断左右孩子谁小的时候我们不需要假定左孩子小这样会有几种情况且很麻烦,所以我们先假定要左孩子小,每次在判断孩子与双亲结点谁小的前面,先拿左孩子右有孩子相互比较,然后我们取小的就行。

        总结算法思想:将父亲结点与孩子结点中小的结点进行比较,然后按照时大堆还是小堆的逻辑进行相互的比较,当孩子结点为叶子结点的时候循环终止。

        插入接口:要保证插入之后我们的堆还是原来的大小堆。

        思想:我们先尾插一个值,然后将这个值进行向上调整,且每次在插入之前我们都需要进行扩容逻辑的判断。

                 代码如下:

                

void PushHeap(HP* php, HeapDataType x)
{
	assert(php);
	//先尾插到数组中去
	//先判断空间是否足够
	if (php->Capacity == php->Size)
	{
		int newcapacity = php->Capacity == 0 ? 4 : php->Capacity * 2;
		HeapDataType* tmp = (HeapDataType*)realloc(php->a, sizeof(HeapDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail:");
			exit(-1);
		 }
		php->a = tmp;
		php->Capacity = newcapacity;
	}

	php->a[php->Size] = x;
	AdjustUp(php->a, php->Size);
	
	php->Size++;
}

        总结:扩容,插入,向上调整,这几个步骤就能将这个接口给实现。

        

        堆的删除接口:这个接口需要借助向下调整算法来解决

                接口作用,能够将二叉树中最大或最小的结点值给删除,让第二大或第二小结点的值展示出来。

        算法思想:我们并不是通过移动空间来将二叉树中根节点的值给删除,因为顺序表的尾插的时间效率非常的大,所以我们一般时首先将根节点的值与最后一个值进行交换,然后再将交换后的结点进行向下调整,这样做可以得到第二大或小的值。

        代码:

        

void PopHeap(HP* php)
{
	assert(php);
	//得有元素才能删除
	assert(php->Size > 0);
	//删除的步骤
	//1先将根结点与尾结点交换,在删除最后一个结点
	
	Swap(&php->a[0], &php->a[(php->Size) - 1]);
	--(php->Size);
	//2在进行向下调整
	AdjustDown(php->a, php->a[0],0);
}

        总结:在删除之前我们还需要看我们的堆是否含有结点,然后在交换,向下调整,就可以完成这个接口了。

        这个接口与判空接口和取堆顶接口,能让我们对我们的数据打印出来是升序的或者是降序的。

        取堆顶元素的接口

                思想:直接返回数组中元素下标为0的值就行

        代码:

        

HeapDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->Size > 0);

	return php->a[0];
}

         判断堆有多少个元素的接口

        直接return size就行

        

int HeapSize(HP* php)
{
	assert(php);
	
	return php->Size;
}

        堆的判空:只需要看size为不为0就行

        

bool HeapEmpty(HP* php)
{
	assert(php);

	return php->Size == 0;
}


        本章结束!!!欢迎大家的耐心观看

        

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

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

相关文章

城市管网污水监测方案,科技助力污水排放管理!

根据《国务院办公厅关于加强入河入海排污口监督管理工作的实施意见》各地要明确“水污染&#xff0c;谁治理”和政府兜底的原则&#xff0c;明确排污主体责任。根据排污口类型集中整治&#xff0c;划分主体。加大私设暗管借道排污的监察力度溯源主体责任。加强科技研发&#xf…

【数据结构】C++实现AVL平衡树

文章目录 1.AVL树的概念2.AVL树的实现AVL树结点的定义AVL树的插入AVL树的旋转左单旋右单旋左右双旋右左双旋插入代码 AVL树的验证AVL树的查找AVL树的修改AVL树的删除AVL树的性能 AVL树的代码测试 1.AVL树的概念 二叉搜索树虽然可以提高我们查找数据的效率&#xff0c;但如果插…

计网第四章(网络层)(八)(最短路径优先协议OSPF)

在第七节&#xff08;计网第四章&#xff08;网络层&#xff09;&#xff08;七&#xff09;_永无魇足的博客-CSDN博客&#xff09;我们总结了路由信息协议RIP。在最后我们提到了RIP协议有坏消息传的慢的问题&#xff0c;这是距离向量算法的本质决定的&#xff0c;所以这种问题…

c语言练习59:深入理解char类型的取值范围

深入理解char类型的取值范围 例如&#xff1a; #include <stdio.h> int main() {char a[1000];int i;for(i0; i<1000; i){a[i] -1-i;}printf("%d",strlen(a));return 0; }结果为255 ab以%d的形式打印结果为&#xff1a;300 而c由于unsigned char的取值范…

【CMU15-445 Part-9】Multi-Threaded Index Concurrency Control

Part09-Multi-Threaded Index Concurrency Control 多线程下索引的并发控制 Concurrency Control 强制所有访问数据结构的线程都使用某种协议或者某种方式。并发控制协议的概念&#xff1a;并发控制协议是一种当并发操作作用在一个共享对象上时DBMS用来确保correct的method。…

【杂记】git管理工具的相关应用

这里记录一些用git管理工具进行开发的命令&#xff0c;便于自己查看&#xff0c;我认为下面两篇博客写的很详细&#xff0c;但是为了自己方便查看&#xff0c;所以自己写了一些命令供自己进一步理解。gitee相对git来说更方便一些&#xff08;毕竟国内的不用担心墙&#xff09;&…

JavaEE 网络原理——TCP的工作机制(初篇 包含 UDP 协议的再次阐述)

文章目录 一、再次简述 UDP 协议二、再次简述 TCP 协议三、描述部分 TCP 内部的工作机制1. 确认应答2. 超时重传 前提&#xff1a; 在前面的文章中&#xff0c;我向大家分别简单介绍了 TCP 协议和 UDP 包装一个数据形成数据报发送信息。 除此之外&#xff0c;还通过代码编写了 …

QT中摄像头的使用

QT中摄像头相关类 摄像头的使用 QT中摄像头的使用主要分为三个方面&#xff0c;显示画面、抓取图片和视频录制。这三个方面对应着摄像模块的三种模式。模式如下&#xff1a; ConstantValueDescriptionQCamera::CaptureViewfinder0相机仅配置为显示取景器。QCamera::CaptureSt…

React入门

一、react开始 1、react是什么 用于构建用户界面的JavaScript库 操作DOM呈现页面 &#xff08;发送请求获取数据和处理数据不由react处理&#xff09;fessbook开发 2、为什么要学 原生js操作DOM繁琐、效率低 使用原生js直接操作DOM&#xff0c;浏览器会进行大量重绘重排 原…

计算机视觉面试题整理

1、介绍目标检测网络yolo系列以及ssd系列的原理&#xff0c;yolo对小目标检测不好的原因&#xff0c;除了缩小anchor外还可以如何改善&#xff1f; Yolo目标检测&#xff1a;YOLO是一种实时目标检测算法&#xff0c;其核心思想是将目标检测问题归为一个回归问题&#xff0c;直…

Android毕业设计,基于Android 语音朗读书籍管理系统

视频演示&#xff1a; 基于Android 语音朗读书籍管理系统 基于 Android 的语音朗读书籍管理系统可以提供用户管理书籍、朗读书籍的功能。以下是一个简单的步骤和功能列表&#xff1a; 用户注册和登录功能&#xff1a; 用户可以注册新账号或使用现有账号登录系统。用户信息可以包…

【rust/egui】(十一)使用rfd选择文件并使用serde_json进行序列化

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 rfd-Rusty File Dialogs 一个跨平台的…

只需3步部署Django项目到Kubernetes上

1. 目标 本文讲述了如何通过3步&#xff0c;把Django项目部署在K8S上。 本文适用读者&#xff1a; 了解Django项目的开发。了解K8S的用途。 2. 具体步骤 把一个Django项目部署在Kubernete环境上&#xff0c;只需以下3步&#xff1a; 创建镜像部署在Kubernetes环境上配置MyS…

linux命令查看谁在使用服务器的GPU

命令&#xff1a;查看GPU使用情况 nvidia-smi 可以知悉GPU占用情况和主要使用GPU的进程&#xff0c;如下图所示&#xff1a; 实时查看gpu使用&#xff1a; nvidia-smi -l 1 表示每隔1s刷新一下&#xff0c;数字可更改。 查看进程的归属者 方法一&#xff1a;ps -f -p pid…

360极速浏览器X终极奥义之——更改划词工具条的搜索为百度搜索 2023更新版

原文为2019版本&#xff0c;具体已失效&#xff0c;2023更新。 1.需要将 https://www.so.com/s?q%s&src360csex_zoned字符串对应的十六进制码替换为 https://www.baidu.com/s?wd%s&src360csex_z对应的十六进制码。 2.需要删除后面的"oned"以保证转换出来…

冒泡排序~

1、对应长度len 数组&#xff0c;需要进行 len -1 趟冒泡&#xff0c;每趟冒泡&#xff0c;将最大&#xff08;小&#xff09;元素排列到最后无序位置 2、每趟冒泡从第一个元素开始&#xff0c;邻近两两比较&#xff0c;找出最大元素 每一趟冒泡&#xff0c;都进行元素交换&am…

基于频谱信息的图像去噪与恢复——使用约束最小二乘方滤波法

大家好&#xff0c;我是带我去滑雪&#xff01; 随着科学技术的不断发展&#xff0c;信息的交流和获取已不再受到时空的限制&#xff0c;已经成为人们日常生活中不可或缺的一部分。图像作为人类信息交流中的重要载体&#xff0c;起着不可替代的作用。频谱图像去噪复原方法是一种…

Hive【Hive(一)DDL】

前置准备 需要启动 Hadoop 集群&#xff0c;因为我们 Hive 是在 Hadoop 集群之上运行的。 从DataGrip 或者其他外部终端连接 Hive 需要先打开 Hive 的 metastore 进程和 hiveserver2 进程。 Hive DDL 数据定义语言 1、数据库&#xff08;database&#xff09; 创建数据库 c…

YOLOv8『小目标』检测指南

前言 目前博主课题组在进行物体部件的异常检测项目&#xff0c;项目中需要先使用 YOLOv8 进行目标检测&#xff0c;然后进行图像切割&#xff0c;最后采用 WinCLIP 模型 进行部件异常检测 但是在实际操作过程中出现问题&#xff0c; YOLOv8 模型目标检测在大目标精确度不错&a…

Vue的详细教程--入门

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Vue的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Vue是什么 二. Vue的特点及优势 三.使用…