数据结构:二叉树、堆

目录

一.树的概念

二、二叉树

1.二叉树的概念

2.特殊类型的二叉树

3.二叉树的性质

4.二叉树存储的结构

三、堆

1.堆的概念

2.堆的实现

Heap.h

Heap.c


一.树的概念

 注意,树的同一层中不能有关联,否侧就不是树了,就变成图了,例如:

由于B和C存在关联,这就不是树了。 

有关树的一些重要概念:

二、二叉树

1.二叉树的概念

二叉树由一个根节点加上两棵别称为左子树和右子树的二叉树组成

它具有两个特点:不存在度大于2的节点;子树有左右之分,次序不能颠倒,故二叉树是有序树

各类型二叉树集合:

2.特殊类型的二叉树

满二叉树:所有非叶子节点都有两个子节点,且所有叶子节点都在同一层

完全二叉树:除了最后一层,每一层都是满的,且最后一层的叶子节点都尽可能靠左排列 

二叉排序树:左子树所有节点的值小于根节点的值,右子树所有节点的值大于根节点的值,且左右子树也分别是二叉排序树

3.二叉树的性质

(1) 对于具有n个节点的完全二叉树,如果按照从上到下从左到右的顺序对所有节点从0开始编号,则序号为i的节点有:其双亲节点序号为(i-1)/2;其左孩子节点序号为i*2+1,右孩子节点序号为i*2+2,注意i*2+1和i*2+2要小于n,合法性

(2)规定根节点层数为1,具有n个节点的满二叉树深度为h=log2(n+1)

(3)规定根节点层数为1,第i层最大节点数为2^(i-1)

(4)规定根节点层数为1,深度为h的二叉树的最大节点数为2^h-1

4.二叉树存储的结构

分为顺序存储结构和链式存储结构,其中用顺序存储结构来实现完全二叉树就是接下来重点介绍的堆。

链式存储:用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。

顺序存储:顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

、堆

1.堆的概念

堆可以看作一种特殊类型的完全二叉树,分为大堆和小堆,根节点最大的称为大堆,根节点最小的称为小堆。

大堆:谁大谁当爹,但兄弟间无绝对大小关系

小堆:谁小谁当爹,但兄第间无绝对大小关系

2.堆的实现

升序:建大堆

降序:建小堆

接下来给出建小堆的代码实现:

Heap.h

#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<stdbool.h>

typedef int HDataType;
typedef struct Heap
{
	HDataType* arr;
	int size;
	int capacity;
}Heap;

//堆的初始化
void HeapInit(Heap* obj);
// 堆的插入
void HeapPush(Heap* obj, HDataType x);
// 堆的删除
void HeapPop(Heap* obj);
// 取堆顶的数据
HDataType HeapTop(Heap* obj);
// 堆的数据个数
int HeapSize(Heap* obj);
// 堆的判空
bool HeapEmpty(Heap* obj);
// 堆的销毁
void HeapDestroy(Heap* obj);

Heap.c

#include"Heap.h"

void HeapInit(Heap* php)
{
	php->capacity = php->size = 0;
	php->arr = NULL;
}

//扩容
void Exp(Heap* obj)
{
	if (obj->size == obj->capacity)
	{
		int new_capeccity = obj->capacity == 0 ? 4 : obj->capacity * 2;
		HDataType* tem = (HDataType*)realloc(obj->arr, sizeof(HDataType) * new_capeccity);
		if (tem == NULL)
		{
			assert("realloc");
		}
		obj->arr = tem;
		obj->capacity = new_capeccity;
	}
}

//交换
void Swap(HDataType* child, HDataType* parent)
{
	HDataType tem = *child;
	*child = *parent;
	*parent = tem;
}

//向上调整
//这里假设是小堆进行调整
//如果是大堆,将if处改为大于号即可
void UpAdjust(HDataType* p,int child)
{
	//通过计算找父母
	HDataType parent = (child - 1) / 2;
	while (child > 0)
	{
		if (p[child] < p[parent])
		{
			//交换
			Swap(&p[child], &p[parent]);
			//交换后,将parent的位置给给child,继续计算下一个parent
			child = parent;//把父母给孩子
			parent = (child - 1) / 2;//得到新的父母
		}
		else
		{
			break;
		}
	}
}

//插入
//先向堆尾插入元素,再根据大堆还是小堆向上调整
void HeapPush(Heap* obj,HDataType x)
{
	assert(obj);
	Exp(obj);
	obj->arr[obj->size] = x;
	obj->size++;
	//这个时候我们需要向上
	UpAdjust(obj->arr, obj->size - 1);
}

//向下调整
//这里假设是小堆
//如果是大堆,将两个if处改为大于号即可
void DownAdjust(HDataType* p,int n,int parent)
{
	//计算出左孩子
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && p[child + 1] < p[child]) {//如果右儿子小于左儿子,直接++到右儿子的位置
			++child;//child+1<n是为了避免越界访问,因为每次算出的是左孩子,堆尾不一定是右孩子
		}
		if (p[child] < p[parent])//如果child<parent,就交换,要把小的往上走
		{
			//这边操作一样,算法不同
			Swap(&p[child], &p[parent]);
			parent = child;//把孩子给父母
			child = parent * 2 + 1;//得到新的孩子
		}
		else
		{
			break;
		}
	}
}

//删除堆顶元素
//这里是小堆,删的实际是最小元素
void HeapPop(Heap* obj)
{
	assert(obj);
	assert(obj->arr);
	assert(obj->size > 0);//堆内无元素则不存在删的问题
	//1.先交换堆顶和堆尾的元素,避免中间节点之间关系全部混乱
	Swap(&obj->arr[0], &obj->arr[obj->size - 1]);
	//2.删
	obj->size--;
	//3.这里我们假设的是小堆,而当前交换后显然不是小堆,故向下调整,将堆中次小元素调到堆顶
	DownAdjust(obj->arr, obj->size, 0);
}

//获取堆顶元素
HDataType HeapTop(Heap* obj)
{
	assert(obj);
	return obj->arr[0];
}

//获取堆中数据的个数
int HeapSize(Heap* obj)
{
	assert(obj);
	return obj->size;
}

//判空
bool HeapEmpty(Heap* obj)
{
	assert(obj);
	return obj->size == 0;
}

//堆的销毁
void HeapDestroy(Heap* obj)
{
	assert(obj);
	assert(obj->arr);
	free(obj->arr);
	obj->arr = NULL;
	obj->capacity = obj->size = 0;
}

test.c

 cl:以上代码和顺序表的实现是很相似的,最大区别是堆独有的特点,也就是建堆,堆尾插入元素时进行向上调整,堆顶删除元素时进行向下调整,这两步是最关键的算法,是保证堆的特点(大小堆)的关键。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# 条形码、二维码标签打印程序

1、条码标答打印主界面 2、打印设置 3、生成QR代码 private void GetBarcode_T(string lr) { QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();//创建一个对象 qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE; //设置编码测量…

汽车票预订系统:SpringBoot技术革新

5系统详细实现 5.1 用户注册 用户需要注册才可以登录。具体界面的展示如图5.1所示。 图5.1 用户注册界面 5.2 汽车票 用户登录后在后台汽车票信息可以进行预定操作。具体界面如图5.2所示。 图5.2 汽车票界面 5.3 订单 用户可以在订单管理里面对订单信息进行换票和支付操作。…

工作日志:vue3各种警告

1、遇见报错&#xff0c;但也没啥影响&#xff0c;不知怎么回事。 可是我没写过这东西啊。 2、一个警告。 它表示在渲染过程中尝试访问组件实例上不存在的属性linkTags。 解决办法&#xff1a;在该属性前&#xff0c;加个v-if判断。 3、 意味着在模板渲染过程中尝试访问了…

MySQL8.0主从同步报ERROR 13121错误解决方法

由于平台虚拟机宿主机迁移&#xff0c;导致一套MySQL主从库从节点故障&#xff0c;从节点服务终止&#xff0c;在服务启动后&#xff0c;恢复从节点同步服务&#xff0c;发现了如下报错&#xff1a; mysql> show slave status\G; *************************** 1. row *****…

前端求职简历-待补充

当然可以&#xff0c;针对大厂的前端岗位&#xff0c;一个吸引人的简历应该突出你的技术能力、项目经验、教育背景以及任何能体现你学习能力和团队协作能力的证明。以下是一个简历大纲示例&#xff0c;你可以根据自己的实际情况进行调整&#xff1a; 个人信息 姓名联系方式&a…

图文深入介绍oracle资源管理(续)

1. 引言&#xff1a; 本文将承接上篇继续深入介绍oracle资源管理。本文重点介绍如何使用oracle资源管理器管理好DB。 2. 资源管理器&#xff1a; 可以使用图形界面 OEM$或命令行调用 DBMS RESOURCE MANAGER 程序包的过程进行数据库资源管理。 调用资源管理器的先决条件&…

【Android】浅析OkHttp(1)

【Android】浅析OkHttp&#xff08;1&#xff09; OkHttp 是一个高效、轻量级的 HTTP 客户端库&#xff0c;主要用于 Android 和 Java 应用开发。它不仅支持同步和异步的 HTTP 请求&#xff0c;还支持许多高级功能&#xff0c;如连接池、透明的 GZIP 压缩、响应缓存、WebSocke…

大模型~合集13

我自己的原文哦~ https://blog.51cto.com/whaosoft/12302606 #TextRCNN、TextCNN、RNN 小小搬运工周末也要学习一下~~虽然和世界没关 但还是地铁上看书吧, 大老勿怪 今天来说一下 文本分类必备经典模型 模型 SOTA&#xff01;模型资源站收录情况 模型来源论文 RAE ​​ht…

STM32外设应用技术博文:基于UART的温度传感器数据采集

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

深入理解Redis锁与Backoff重试机制在Go中的实现

文章目录 流程图Redis锁的深入实现Backoff重试策略的深入探讨结合Redis锁与Backoff策略的高级应用具体实现结论 在构建分布式系统时&#xff0c;确保数据的一致性和操作的原子性是至关重要的。Redis锁作为一种高效且广泛使用的分布式锁机制&#xff0c;能够帮助我们在多进程或分…

构建高效在线考试平台:Spring Boot与JavaWeb的融合

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于JavaWeb技术的在线考试系统设计与实现…

汽车零部件行业CRM应用数字化解决方案解析

1.行业背景与挑战分析 近年来&#xff0c;随着国家对新能源汽车行业的大力支持&#xff0c;国内汽车产业不仅在国内市场实现了弯道超车&#xff0c;而且新能源汽车的海外出口也开拓了新的市场&#xff0c;为自主品牌的新能源战略贡献了新的增长点&#xff1b;这一迅猛发展的趋…

Pollard‘s p-1算法

概述 光滑数 (Smooth number)&#xff1a;指可以分解为多个小素数乘积的正整数 当p是N 的因数&#xff0c;并且p−1是光滑数&#xff0c;可以考虑使用Pollards p-1算法来分解N 当p是N的因数&#xff0c;并且p1是光滑数&#xff0c;可以考虑使用Williamss p1算法来分解N 这里…

打造卓越APP体验:13款界面设计软件推荐

你知道如何选择正确的UI设计软件吗&#xff1f;你知道设计美观的用户界面&#xff0c;及带来良好用户体验的APP&#xff0c;需要什么界面设计软件吗&#xff1f;基于APP界面的功能不同&#xff0c;选择的APP界面设计软件也会有所不同。然而&#xff0c;并不是要把所有APP界面设…

权限(补充)

在上一篇Linux权限&#xff08;想了解的可以点击看看哦&#xff09;中已经见识了一部分权限&#xff0c;但是少了很重要的一部分&#xff1a; 那就是用户之间的转换&#xff0c;文件读写的关系&#xff0c;这里就简单的介绍一些&#xff1b; 我们在Linux权限知道了目录权限的关…

无人机之放电速率篇

无人机的放电速率是指电池在一定时间内放出其储存电能的能力&#xff0c;这一参数对无人机的飞行时间、性能以及安全性都有重要影响。 一、放电速率的表示方法 放电速率通常用C数来表示。C数越大&#xff0c;表示放电速率越快。例如&#xff0c;一个2C的电池可以在1/2小时内放…

屏蔽小米电视广告的方法

小米电视那个广告&#xff0c;太多&#xff0c;时间太长&#xff0c;影响观看感受&#xff0c;经过处理&#xff0c;成功屏蔽了小米电视的广告&#xff0c;提升了观影体验。 手动添加AD域名到 hosts 列表 小米(红米)电视关闭开机AD屏蔽hosts方法。 在路由器的hosts中配置。 …

Redis --- 第四讲 --- 常用数据结构 --- Hash、List

一、Hash哈希类型的基本介绍。 哈希表&#xff1a;之前学过的所有数据结构中&#xff0c;最最重要的。 1、日常开发中&#xff0c;出场频率非常高。 2、面试中&#xff0c;非常重要的考点。 Redis自身已经是键值对结构了。Redis自身的键值对就是通过哈希的方式来组织的。把…

12月17-19日 | 2024南京软博会,持续升级中!

2024中国&#xff08;南京&#xff09;软件产业博览会&#xff08;简称“南京软博会”&#xff09;自2005年以来&#xff0c;已连续举办19年&#xff0c;集新品发布、产品交易、人才交流、项目对接等功能为一体&#xff0c;成为全国软件产业品牌展会和对外窗口。 今年是南京软…

ubuntu 安装keepalived+haproxy

一、安装keepalived sudo apt update sudo apt install keepalived sudo systemctl start keepalived sudo systemctl enable keepalived sudo systemctl status keepalived#配置Keepalived sudo cp /etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf …