快速学习初阶“堆“(数据结构C语言)

news2024/12/23 18:04:31

前言:

        二叉树是什么?

        同样也和之前的"栈"跟"队列"是一样的,是一种存储数据的方式,只不过二叉树的结构更为复杂。

        那么为什么要用二叉树存储数据呢?真的多此一举吗?

        它的实际作用是什么呢?

堆:

树的定义:

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。


有一个特殊的结点,称为根结点,根节点没有前驱结点


除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继因此,树是递归定义的。

节点的度:一个节点含有的子树的个数称为该节点的度;
叶节点或终端节点:度为0的节点称为叶节点; 
非终端节点或分支节点:度不为0的节点;
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; :一个节点含有的子树的根节点称为该节点的子节点; 
兄弟节点:具有相同父节点的节点互称为兄弟节点; 
树的度:一棵树中,最大的节点的度称为树的度; 
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次;
堂兄弟节点:双亲在同一层的节点互为堂兄弟;
节点的祖先:从根到该节点所经分支上的所有节点;
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
森林:由m(m>0)棵互不相交的树的集合称为森林;

二叉树的定义:

        二叉树是特殊的树,满足以下特点:

1. 二叉树不存在度大于2的结点
2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

例如:

两种特殊的二叉树:

1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

例如:

堆的定义:

        如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: <= 且 <=  ( >= 且 >= ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

        堆首先是一个完全二叉树,并且满足以下条件:


堆中某个节点的值总是不大于或不小于其父节点的值;

当堆中某个节点的值总大于其父亲结点的值,称为大堆

当堆中某个节点的值总大于其父亲结点的值,称为小堆

例如:

堆的实现:

        由于堆的实现可以用链表实现,但是同样可以用顺序表实现,在这里由于是初阶,首选利用顺序表实现。

        利用顺序表实现堆需要进行有序存储。

        例如存储一个小堆:

通过观察,双亲的下标和子节点的下标关系是:

双亲下标 = (子节点下标 -1)/2;

左孩子节点下标 = 双亲下标*2+1;

右孩子节点下标 = 双亲下标*2+2;

Heap.h文件中定义结构体及函数的声明:
   

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;
//初始化堆
void HeapInit(Heap* hp);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);

     这里结构体的定义,函数的声明不做过多的解释。

在之前的数据结构中都有一定的说明。

(主要是懒

Heap.c文件中实现函数的定义:

初始化堆:
        

        在未开辟空间之前将指针置为NULL,capacity 与size 置为0。

void HeapInit(Heap* hp)
{
	assert(hp);
	hp->_a = NULL;
	hp->_capacity = hp->_size = 0;
}

销毁堆:

        话不多说直接写:

void HeapDestory(Heap* hp)
{
	assert(hp);
	free(hp->_a);
	hp->_a = NULL;
	hp->_capacity = hp->_size = 0;
}

 堆的插入:

建大堆:

先画图,分析一下:

先插入一个3,再插入一个10

发现10比3大,也就是孩子比双亲大,需要交换。

双亲下标 = (子节点下标 -1)/2;

左孩子节点下标 = 双亲下标*2+1;

右孩子节点下标 = 双亲下标*2+2;

再插入一个8。

再插入一个15。

此时需要交换一次双亲节点和孩子节点。

此时还是需要交换一次双亲节点和孩子节点。

以上的过程称之为向上调整!

每插入一个值之后就需要进行向上调整!!

void swap(HPDataType *a, HPDataType *b)
{
	HPDataType c = 0;
	c = *a;
	*a = *b;
	*b = c;
}
void AdjustUp(HPDataType *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;
		}
	}
}
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	if (hp->_capacity == hp->_size)
	{
		int newcapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(hp->_a ,newcapacity*sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("malloc::error");
			exit(-1);
		}
		hp->_capacity = newcapacity;
		hp->_a = tmp;
	}
	hp->_a[hp->_size] = x;
	hp->_size++;
	AdjustUp(hp->_a,hp->_size-1);
}

堆的删除:

        堆的删除是从对堆顶开始删除,但是删完之后大堆的顺序会变得混乱,该怎么办?

画图分析:

如果直接删除,结果会是这样:

此时发现空出了一个位置,也就不满足完全二叉树了!!

不适合这样删数据。

第一步首先应该将需要删除的堆顶的数据与堆底进行交换

直接size--,然后变成这样:

之后进行向下调整,当双亲结点的值小于左孩子与右孩子的最大值时交换

继续进行:

直到双亲节点>size为止。

代码如下:

void AdjustDown(HPDataType* a, int size, int parent)
{
	//假设最大的孩子的值是左孩子对应的数值
	int childmax = (parent * 2) + 1;
	while (childmax<size)
	{
		//如果右有孩子并且右孩子的值是大于左孩子将最大的孩子换成右孩子
		if (childmax + 1 < size && a[childmax + 1] > a[childmax])
		{
			childmax = childmax + 1;
		}
		if (a[parent] < a[childmax])
		{
			swap(&a[parent], &a[childmax]);
			parent = childmax;
			childmax = (parent * 2) + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapPop(Heap* hp)
{
	assert(hp);
	swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
	hp->_size--;
	AdjustDown(hp->_a,hp->_size,0);
}

取堆顶的数据:

HPDataType HeapTop(Heap* hp)
{
	assert(hp);
	assert(hp->_size);
	return hp->_a[hp->_size - 1];
}

堆的数据个数:

int HeapSize(Heap* hp)
{
	assert(hp);
	return hp->_size;
}

堆的判空:
 

// 堆的判空
int HeapEmpty(Heap* hp)
{
	assert(hp);
	return hp->_size == 0;
}

test.c中实现堆:
 

#include"Heap.h"
void test1()
{
	Heap hp;
	int arr[] = {1,2,3,4,5,6,7,8};
	HeapInit(&hp);
	int i = 0;
	//插入并调整
	for (i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		HeapPush(&hp, arr[i]);
	}
	//输出并删除
	while (!HeapEmpty(&hp))
	{
		printf("%d ", HeapTop(&hp));
		HeapPop(&hp);
	}
	HeapDestory(&hp);
}

int main()
{
	test1();
	return 0;
}

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

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

相关文章

买对不买贵,宠物空气净化器应该怎么选才能选到好的产品

你是否还在为家中无处不在的猫毛而烦恼&#xff1f;每当有风吹来&#xff0c;就把四处躲藏的猫毛给吹出来&#xff0c;不经意间就可能让这些”蒲公英“悄悄附在你的食物上&#xff0c;或是不经意间吸入鼻腔&#xff0c;让人既无奈又尴尬。你是否每天下班回家后的第一件事&#…

AnyV2V:一种用于各种视频编辑任务的即插即用框架

人工智能咨询培训老师叶梓 转载标明出处 视频编辑任务通常涉及根据额外的控制信息&#xff08;如文本提示、主题、风格等&#xff09;编辑源视频&#xff0c;以生成与源视频和提供的控制信息相符的新视频。然而&#xff0c;现有方法往往局限于特定类型的编辑任务&#xff0c;难…

面向对象06:super关键字详解

本节内容视频链接&#xff1a;面向对象10&#xff1a;Super详解_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p69&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 Java中的‌super关键字是一个特殊的引用&#xff0c;‌用于指代父类对象‌。‌在子…

搜维尔科技:Xsens通过其先进的动作捕捉技术和惯性跟踪传感器,实现了与机器人的高效互动,提高了机器人的操作精度、自然性和稳定性

‌Xsens通过实时动作捕捉技术和MTI惯性跟踪传感器与机器人进行互动‌&#xff0c;这些技术为机器人提供了高精度的运动数据和稳定的导航能力&#xff0c;从而实现了机器人操作的精确性和效率的提升。 Xsens的技术主要应用于两大领域&#xff1a;人类物理交互行为的建模和分析&a…

如何使用ssm实现基于java的小型超市管理系统+vue

TOC ssm195基于java的小型超市管理系统vue 绪论 1.1 研究背景 现在大家正处于互联网加的时代&#xff0c;这个时代它就是一个信息内容无比丰富&#xff0c;信息处理与管理变得越加高效的网络化的时代&#xff0c;这个时代让大家的生活不仅变得更加地便利化&#xff0c;也让…

Git 的配置

1. 忽略特殊文件 在⽇常开发中&#xff0c;我们有些⽂件不想或者不应该提交到远端&#xff0c;⽐如保存了数据库密码的配置⽂件&#xff0c;那怎么让 Git 知道呢&#xff1f;在 Git ⼯作区的根⽬录下创建⼀个特殊的 .gitignore ⽂件&#xff0c;然后把要忽略的⽂件名填进去&am…

【中仕公考怎么样】2025年山东各考试汇总

准备同时备考山东多项考试的考生看过来啦!本篇文章带大家了解一下2025年山东省各项考试时间节点! ①国考 公告发布:2024年10月14日(参考去年) 笔试时间:11月下旬 笔试内容:行测申论&#xff0c;部分有专业科目;面试形式:结构化 ②省考 公告发布:2024年11月 笔试时间:202…

Unet改进8:在不同位置添加SpatialGroupEnhance||空间群智能增强:改进卷积网络中的语义特征学习

本文内容:在不同位置添加SpatialGroupEnhance 论文简介 卷积神经网络(Convolutional Neural Networks, cnn)通过收集分层的、不同部分的语义子特征来生成复杂对象的特征表示。这些子特征通常以分组的形式分布在每一层的特征向量中[43,32],代表各种语义实体。然而,这些子特征…

python --cnlunar(黄历)

import datetime import cnlunara cnlunar.Lunar(datetime.datetime(2024, 8, 26, 10, 30), godType8char) # 常规算法 # a cnlunar.Lunar(datetime.datetime(2022, 2, 3, 10, 30), godType8char, year8CharbeginningOfSpring) # 八字立春切换算法 dic {日期: a.date,农历…

如何使用ssm实现毕业生就业管理平台

TOC ssm192毕业生就业管理平台jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理…

如何使用ssm实现保险业务管理系统设计与实现

TOC ssm131保险业务管理系统设计与实现jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规…

Pytorch构建网络模型结构都有哪些方式

目录 前言 1.使用nn.Module基类 2.使用nn.Sequential容器 3. 使用nn.ModuleList 4. 使用nn.ModuleDict 5. 混合使用nn.Module和原生Python代码 6.表格总结 前言 nn.Module&#xff1a;最通用、最灵活的方式&#xff0c;适用于几乎所有场景。nn.Sequential&#xff1a;适…

基于Springboot/Vue的企业内部培训考试系统

本系统不开源&#xff01; 本系统不开源&#xff01; 本系统不开源&#xff01; 前言&#xff1a; 时间宝贵的朋友直接跳过这段进入主题吧。 首先&#xff0c;好久没有静心写点东西了&#xff0c;有些经验之谈、生活经历以及一些规划和感悟吧&#xff0c;大体写一下就当自我…

Linux下编译安装PETSc

本文记录在Linux编译安装PETSc的流程。 1 下载代码 git clone https://gitlab.com/petsc/petsc.git cd ./petsc git checkout v3.21.4 2 安装依赖 3 PETSc Without MPI 3.1 Debug版本 3.1.1 配置 export PETSC_ARCHarch-linux-c-debug-dto python3 ./configure --prefix/…

水凝胶与柔性电子啥关系?能用来干啥?

大家好&#xff0c;今天我们来聊一聊一篇关于水凝胶在柔性电子领域应用的文章——《Smart materials for flexible electronics and devices: hydrogel》发表于《RSC Advances》。随着科技的不断发展&#xff0c;柔性电子设备越来越受到关注&#xff0c;而水凝胶作为一种具有独…

python-小理和01串(赛氪OJ)

[题目描述] 小理有一个 01 串&#xff0c;串中只包含 0 和 1 &#xff0c;小理要把这个串划分成连续的 m 段&#xff0c;使得每一段至少包含一个 0 和一个 1 。小理想最大化 m &#xff0c;m 最大是多少呢&#xff1f;输入格式&#xff1a; 输入包含一行一个 01 串 S 。保证中至…

OpenCV绘图函数详解及其用法示例

MFC类库中的CDC类有划线,画矩形,画椭圆,画多边形,文字等绘图函数,OpenCV也有类似的绘图函数。二者的区别在于MFC画图是在一定的区域内绘制图形,而OpenCV则是在图像上绘制,主要用于图像标注。 OpenCV的常用绘图函数有arrowedLine,circle ,drawContours, drawMarker, dra…

Date.now()与performance.now()

前言 Date.now() 和 performance.now() 都是 JS 中用于获取当前时间的方法&#xff0c;本文将讲述二者的区别与优劣。 Date.now() 返回自 Unix 时间纪元&#xff08;1970年1月1日 00:00:00 UTC&#xff09;以来的毫秒数。 在大多数环境下&#xff0c;Date.now() 的精度为 1毫…

Spring Cloud Consul精选面试题及答案

Spring Cloud Consul 面试题及答案&#xff1a; 1. 什么是Spring Cloud Consul&#xff1f; 答&#xff1a;Spring Cloud Consul 是一个基于 Spring Boot 和 Spring Cloud 的微服务框架&#xff0c;用于实现服务发现、配置中心和负载均衡等功能。Consul 是 HashiCorp 公司开源…

【C/C++】Sleep()函数详解

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Visual Studio 2022 / Xshell (操作系统:CentOS 7.9 64位) 目录 &#x1f4cc;Windows系统下Sleep()函数简介 &#x1f38f;函数功能 &#x1f38f;函数参数 &#x1f579;️DWORD milliseconds &…