【C++】树和二叉树的实现(下)

news2025/3/19 13:46:55

本篇博客给大家带来的是用C++语言来实现数据结构树和二叉树的实现!

🐟🐟文章专栏:数据结构

🚀🚀若有问题评论区下讨论,我会及时回答

❤❤欢迎大家点赞、收藏、分享!

今日思想:你现在的懒惰将来你会买单的!

         续接上文【C++】树和二叉树的实现(上)-CSDN博客

 一、二叉树的实现方法

         在上文我们知道二叉树有两种方法(顺序结构和链式结构),顺序结构实现二叉树的底层是数组,那么在现实生活中我们把堆(一种二叉树)使用顺序结构来存储,最后二叉树的实现方法有:堆的初始化、堆的销毁、向上调整、向下调整、入堆、出堆、判断堆是否为空、取堆顶数据。接下来我们一一实现。

        1、堆的初始化

        既然堆的底层是数组,那么我们先确定堆的结构体。

代码实例:

//Heap.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

//堆的结构
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* arr;
	int size;//有效数据个数
	int capacity;//空间大小
}HP;

堆的初始化:

//Heap.h
//堆的初始化
void HPInit(HP* php);
//Heap.c
#include"Heap.h"
//堆的初始化
void HPInit(HP* php)
{
	assert(php);
	php->arr = NULL;
	php->size = php->capacity = 0;
}

         2、堆的销毁

        堆的销毁和初始化差不多这里不展开说。

代码实例:

//Heap.h
//堆的销毁
void HPDestory(HP* php);
//堆的销毁
void HPDestory(HP* php)
{
	assert(php);
	if (php->arr)
		free(php->arr);
	php->arr = NULL;
	php->size = php->capacity = 0;
}

        3、向上调整

        我们有个堆假设是小堆(如图),如果我们在size位置插入0,那么这样就不符合小堆的结 构,所以我们要向上调整。上偏文章我们可知二叉树的特点:如果 i 是孩子下标,父结点下标等于(i-1)/ 2,假设 i 为父结点下标那么右孩子下标等于2i+2,左孩子等于2i+1。

        思路:通过插入数据的下标求父结点的下标然后对比父结点和孩子结点的大小来判断是否符合小堆结构,不符合就交换。

代码实例:

//Heap.h
//向上调整
void AdjustUp(HPDataType* arr, int child);
//交换两个值
void Swap(HPDataType* x, HPDataType* y);
//Heap.c
//交换两个值
void Swap(HPDataType* x, HPDataType* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;

//向上调整
void AdjustUp(HPDataType* arr, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		//小堆: <
        //大堆: >
        if (arr[child] < arr[parent])
		{
			swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

        4、入堆

        入堆的思想和向上调整差不多,只要我们往数组的size位置插入数据,首先我们要判断空间是否满了,如果满了申请新的空间,没有就插入然后向上调整,如果是小堆就要返回小堆的结构。

代码实例:

//Heap.h
//入堆
void HPPush(HP* php, HPDataType x);
//Heap.c
//入堆
void HPPush(HP* php, HPDataType x)
{
	assert(php);
	//判断空间是否足够
	if (php->size == php->capacity)
	{
		//增容
		int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
		HPDataType* tmp = (HPDataType*)realloc(php->arr, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		php->arr = tmp;
		php->capacity = newCapacity;
	}
	//空间足够直接插入
	php->arr[php->size] = x;
	//向上调整
	AdjustUp(php->arr, php->size);
	++php->size;
}

5、向下调整

        向下调整和出堆联动,大家可以先看下面的出堆,根据出堆我们把堆顶和最后的数据交换,假设这是个大堆,而10在堆顶(如图),这不符合大堆的结构,我们需要向下调整。

思路:根据10的下标来找10的右孩子和左孩子,左孩子和右孩子比较谁大和父结点交换,交换完之后再让parent来到child的位置,child来到25的位置然后重复操作。

代码实例:

//Heap.h
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n);
//Heap.c
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//大堆: <
		//小堆: >
		if (child + 1 < n && arr[child] < arr[child + 1])
		{
			child++;
		}
		//大堆:>
		//小堆:<
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}

6、出堆与判断堆是否为空

        出堆其实就是把堆顶的数据和最后一个数据交换,然后size--;到时候如果插入新数据就可以覆盖最后的数据,size--之后要向下调整保证符号堆(大堆或者小队)的结构。

代码实例:

//Heap.h
//出堆
void HPPop(HP* php);
//判断堆是否为空
bool HPEmpty(HP* php);
//Heap.c
//判断堆是否为空
bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}
//出堆
void HPPop(HP* php)
{
	assert(!HPEmpty(php));
	swap(&php->arr[0], &php->arr[php->size - 1]);
	php->size--;
	//向下调整
	AdjustDown(php->arr, 0, php->size);
}

 7、堆的打印

        有时候我们需要打印堆来看看是否符号自己的预期。

代码实例:

//Heap.h
//堆的打印
void HPPrint(HP* php);
//Heap.c
//堆的打印
void HPPrint(HP* php)
{
	for (int i = 0; i < php->size; i++)
	{
		printf("%d ", php->arr[i]);
	}
	printf("\n");
}

8、取堆顶数据

        取堆顶的数据就是数组下标为0的数据。

代码实例:

//Heap.h
//取堆顶数据
HPDataType HPTop(HP* php);
//Heap.c
//取堆顶数据
HPDataType HPTop(HP* php)
{
	assert(!HPEmpty(php));
	return php->arr[0];
}

9、完整的代码

//Heap.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

//堆的结构
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* arr;
	int size;//有效数据个数
	int capacity;//空间大小
}HP;

//堆的初始化
void HPInit(HP* php);
//堆的销毁
void HPDestory(HP* php);
//堆的打印
void HPPrint(HP* php);
//交换两个值
void Swap(HPDataType* x, HPDataType* y);
//向上调整
void AdjustUp(HPDataType* arr, int child);
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n);
//入堆
void HPPush(HP* php, HPDataType x);
//出堆
void HPPop(HP* php);
//取堆顶数据
HPDataType HPTop(HP* php);
//判断堆是否为空
bool HPEmpty(HP* php);
//Heap.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
//堆的初始化
void HPInit(HP* php)
{
	assert(php);
	php->arr = NULL;
	php->size = php->capacity = 0;
}
//堆的销毁
void HPDestory(HP* php)
{
	assert(php);
	if (php->arr)
		free(php->arr);
	php->arr = NULL;
	php->size = php->capacity = 0;
}
//交换两个值
void Swap(HPDataType* x, HPDataType* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
//向上调整
void AdjustUp(HPDataType* arr, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		//小堆: <
		//大堆: >
		if (arr[child] > arr[parent])
		{
			swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
//入堆
void HPPush(HP* php, HPDataType x)
{
	assert(php);
	//判断空间是否足够
	if (php->size == php->capacity)
	{
		//增容
		int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
		HPDataType* tmp = (HPDataType*)realloc(php->arr, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		php->arr = tmp;
		php->capacity = newCapacity;
	}
	//空间足够直接插入
	php->arr[php->size] = x;
	//向上调整
	AdjustUp(php->arr, php->size);
	++php->size;
}
//判断堆是否为空
bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//大堆: <
		//小堆: >
		if (child + 1 < n && arr[child] < arr[child + 1])
		{
			child++;
		}
		//大堆:>
		//小堆:<
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
//出堆
void HPPop(HP* php)
{
	assert(!HPEmpty(php));
	swap(&php->arr[0], &php->arr[php->size - 1]);
	php->size--;
	//向下调整
	AdjustDown(php->arr, 0, php->size);
}
//堆的打印
void HPPrint(HP* php)
{
	for (int i = 0; i < php->size; i++)
	{
		printf("%d ", php->arr[i]);
	}
	printf("\n");
}
//取堆顶数据
HPDataType HPTop(HP* php)
{
	assert(!HPEmpty(php));
	return php->arr[0];
}

完!!

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

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

相关文章

kafka指北

为自己总结一下kafka指北&#xff0c;会持续更新。创作不易&#xff0c;转载请注明出处。 目录 集群controller选举过程broker启动流程 主题创建副本分布ISRleader副本选举机制LEO 生产数据流程同步发送和异步发送 分区策略ack应答生产者发送消息的幂等性跨分区幂等性问题&…

7、vue3做了什么

大佬认为有何优点&#xff1a; 组合式api----逻辑集中、对ts有更好的支持RFC–开放了一个讨论机制&#xff0c;可以看到每一个api的提案&#xff0c;方便源码维护&#xff0c;功能扩展&#xff0c;大家一起讨论 官方rfc响应式独立&#xff0c;new Proxy&#xff0c;天生自带来…

基于大语言模型与知识图谱的智能论文生成工具开发构想

基于大语言模型与知识图谱的智能论文生成工具开发构想 一、研究背景与意义 1.1 学术写作现状分析 #mermaid-svg-FNVHG5EiEgVSCpHK {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-FNVHG5EiEgVSCpHK .error-icon{fil…

JUC大揭秘:从ConcurrentHashMap到线程池,玩转Java并发编程!

目录 JUC实现类 ConcurrentHashMap 回顾HashMap ConcurrentHashMap CopyOnWriteArrayList 回顾ArrayList CopyOnWriteArrayList: CopyOnWriteArraySet 辅助类 CountDownLatch 线程池 线程池 线程池优点 ThreadPoolExecutor 构造器各个参数含义&#xff1a; 线程…

4.3--入门知识扫盲,IPv4的头部报文解析,数据报分片,地址分类(包你看一遍全部记住)

IPv4协议&#xff1a;网络世界的快递包裹指南&#xff08;附拆箱说明书&#xff09; “IPv4就像一张明信片&#xff0c;既要写清楚地址&#xff0c;又要控制大小别超重” —— 某网络工程师的桌面铭牌 一、IPv4报头&#xff1a;快递面单的终极艺术 1.1 报头结构图&#xff08;…

苍穹外卖-阿里云OSS使用

第一步&#xff1a; package com.sky.properties;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component;Component ConfigurationProperties(prefix "sky.alioss") …

Vue生命周期_Vue生命周期钩子

一、生命周期介绍 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置好数据侦听&#xff0c;编译模板&#xff0c;挂载实例到 DOM&#xff0c;以及在数据改变时更新 DOM。 在此过程中&#xff0c;它也会运行被称为生命周期钩子的函数&#xff0c;让…

数据库设计实验(4)—— 数据更新实验

一、目的与要求 掌握用SQL语句实现数据的插入、修改和删除。 二、实验准备 1. 建立一个商店的数据库store&#xff0c;记录顾客及其购物情况&#xff0c;由下面三个表组成&#xff1a; 商品&#xff08;商品号&#xff0c;商品名&#xff0c;单价&#xff0c;商品类别&#x…

Apache DolphinScheduler:一个可视化大数据工作流调度平台

Apache DolphinScheduler&#xff08;海豚调度&#xff09;是一个分布式易扩展的可视化工作流任务调度开源系统&#xff0c;适用于企业级场景&#xff0c;提供了一个可视化操作任务、工作流和全生命周期数据处理过程的解决方案。 Apache DolphinScheduler 旨在解决复杂的大数据…

再学:call与delegatecall、call转账 Bank合约

目录 1.call与delegatecall 2.transfer && call 3.若想内部传递abi编码 4.Bank合约 1.call与delegatecall call&#xff1a;切换上下文 delegatecall&#xff1a;不切换上下文 delegatecall可以理解为 A在调用B这个集成在A的方法 可升级合约&#xff0c;常用del…

关于解决新版本spring项目请求测试接口返回406的问题

目录 一、问题产生 二、问题排查 &#xff08;1&#xff09;首先是打断点debug进行排查 &#xff08;2&#xff09;网上查找相关资料排查 &#xff08;3&#xff09;老项目测试 三、问题解决 一、问题产生 使用Apifox对后端发送请求进行接口测试时返回状态码406&#xff0…

linux入侵排查_应急响应

1.实验目标 掌握linux系统中信息收集的方法 掌握linux系统中持久化操作方法及排查方式 掌握linux系统入侵排查思路 2.实验步骤 1.统计攻击者爆破次数 2.排查攻击者第一次使用恶意用户登录的时间 3.检查sudoer文件 4.排查计划任务 5.排查计划任务 6.排查恶意服务 7.排查…

AI视频生成产品体验分享(第2趴):Vidu、Hailuo、Runway、Pika谁更胜一筹?

hi&#xff0c;大家&#xff0c;继上次体验完可灵、即梦和pixverse&#xff0c;今天打算从产品经理的角度再研究下Vidu、Hailuo、Runway、Pika这几款产品&#xff01;欢迎加入讨论&#xff01; 一、产品简介 1. Vidu&#xff1a;国产自研的「一致性标杆」 &#x1f4cc;官网…

R语言高效数据处理-自定义格式EXCEL数据输出

注&#xff1a;以下代码均为实际数据处理中的笔记摘录&#xff0c;所以很零散&#xff0c; 将就看吧&#xff0c;这一篇只是代表着我还在&#xff0c;所以可能用处不大&#xff0c;这一段时间都很煎熬&#xff01; 在实际数据处理中为了提升效率&#xff0c;将Excel报表交付给…

基于srpingboot高校智慧校园教学管理服务平台的设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

【小白向】Word|Word怎么给公式标号、调整公式字体和花括号对齐

【小白向】Word&#xff5c;Word怎么给公式标号、调整公式字体和花括号对齐 我的版本&#xff1a;Word 2021 如需快速查看关键步骤&#xff0c;请直接阅读标红部分。 如果遇到无法调整的情况&#xff0c;可以直接下载我的示例文档进行参考&#xff1a;花括号和其他的示例公式.…

js逆向-下载某音乐

首先点击播放音乐&#xff0c;会拿到这样一个数据包 ​ 查看参数两个参数都是加密的 ​ 返回包里面有一个url&#xff0c;url拿到访问发现就是音频链接 ​ 访问直接下载下来 ​ 要逆向这两个参数采用xhr断点 ​ 这里加上路径的一部分 ​ 发现这些参数都是加密的 ​ 往下跟栈&am…

百度OCR调用记录

根据说明&#xff0c;调用测试 设置注册的API Key和Secret Key 调用类&#xff08;官方文档中有&#xff09; 这里改传入路径&#xff1b; 测试问题 1.{"error_code":110,"error_msg":"Access token invalid or no longer valid"} 查到说是 …

项目实战:基于瑞萨RA6M5构建多节点OTA升级-创建系统最小框架<三>

MCUBoot项目创建完成后,接下来我们需要搭建多节点OTA系统最小框架,再将系统分模块搭建逐层完善,直到实现最终完整系统。开始动手干吧! 目录 一、创建项目 ​二、配置FSP ​2.1 配置RS485属性 ​2.2 配置定时器0 2.3 创建初始化进程并配置属性 ​2.4 创建RS485进程并…

C/C++模版初阶

文章目录 C/C模版初阶泛型编程函数模版函数模版概念函数模版格式函数模版的原理函数模版的实例化模版参数的匹配原则 类模版类模版的定义格式类模版的实例化 结语 我们今天又见面了&#xff0c;给生活加点<font colorred>impetus&#xff01;&#xff01;开启今天的编程之…