二叉树——堆

news2024/10/1 21:30:17

一,树的概念及结构

1.树

4.结点的度:一个节点含有子树的个数称为该结点的度;如:A 的度为6.

5.叶节点或终端节点:度为0的节点称为叶节点;如:B

6.非终端结点或分支节点:度部位0的结点;如:D

7.双亲结点或父节点:若一个结点含有子节点,则这个节点称为其子节点的父节点;如:A是B的8.父节点。

8.孩子节点或子节点:一个结点含有的子树的根结点称为该节点的子节点;如:B是A的函子结点。

9.兄弟节点:具有相同的父结节点称为兄弟节点;如上图:B,C是兄弟节点。

10.树的度:一颗树中,最大使得节点称为树的度;如:上图树的度为6。

11.节点的层次:从根节点定义起,根为第一层,根的子节点为第二层,以此类推。

12.堂兄弟节点:双亲在同一层的节点互为堂兄弟。如:H,I互为堂兄弟。

13.节点的祖先:从根到该节点所经分支上的所有节点。如:A是所有节点的祖先。

14.子孙:以某节点为跟的子树中任意节点都称为该节点的子孙,如:所有的节点都是A的子孙。

15.森林:有m(m>0)棵互不相交的属的集合称为森林。

 2.二叉树

1.二叉树结点度最大为2。

2.二叉树子树左右次序不能颠倒,二叉树是有序树。

(1)满二叉树

二叉树的每层节点数都达到最大值。

(2)完全二叉树

二叉树深度为h,除第n层外,其他层的节点数都达到最大,而且h层所有的结点都集中在左层。

 (3)二叉树的性质

设根节点层数为1

1.非空二叉树i层最多有2^(n-1)个结点。

2.深度为h的二叉树最多有2^h -1个结点。

3.二叉树储存结构

1.顺序结构

用数组储存,物理上是数组,逻辑上是二叉树。

 2.链式储存

用链表表示二叉树,表的每个节点由数据和左右指针(对应左右孩子)组成,可以分为二叉链表和三叉链表。

 二叉链表                                        三叉链表

二叉树                        二叉链表                                三叉链表 

二,实现二叉树顺序结构

1.堆

        只有大堆和小堆

        堆是完全二叉树

2.实现堆

创建结构体

//创建小堆
typedef int HPDataType;
 
//以数组的形式实现完全二叉树
 
typedef struct Heap
{
	HPDataType* a;//创建指针数组
	size_t capacity;//容量
	size_t size;//大小
}HP;

初始化

类比顺序表

//初始化
void HPInit(HP* php)
{
	//断言,防止传递的指针为野指针
	assert(php);
	//初始化
	php->a = NULL;
	php->capacity = php->size = 0;
}

销毁堆

//销毁
void HPDestroy(HP* php)
{
	//断言
	assert(php);
	//释放申请的内存
	free(php->a);
	php->a = NULL;
	//置空
	php->capacity = php->size = 0;
}

插入数据

向上调整:先将数据插入到堆中,向上调整。找到子节点和这个子节点的父亲,比较大小。交换父亲和孩子结点的值,循环下去,child位于祖先结点时,循环结束。

void Swap(HPDataType* a, HPDataType* b)
{
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}
 
void AdjustUp(HPDataType* a, size_t child)
{
	//找到子节点,以及这个孩子的父亲
	size_t parent = (child - 1) / 2;
	//比较父亲和孩子的大小
	while (child > 0)
	{
		if (a[parent] > a[child])
		{
			Swap(&a[parent], &a[child]);
		}
		else
		{
			break;
		}
		child = parent;
		parent = (child - 1) / 2;
	}
}
//插入数据,保证堆还是小/大堆
void HPPush(HP* php, HPDataType x)
{
	//断言
	assert(php);
	//判断是否要扩容
	if (php->capacity == php->size)
	{
		size_t newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		//realloc动态开辟空间
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		else
		{
			php->a = tmp;
			php->capacity = newcapacity;
		}
	}
	//插入数据
	php->a[php->size] = x;
	php->size++;
 
	//向上调整堆,保证其还是一个小堆
	AdjustUp(php->a, php->size - 1);
}

打印“堆”

void HPPrint(HP* php)
{
	for (size_t i = 0; i < php->size; i++)
	{
		printf("%d ", php->a[i]);
	}
	printf("\n");
}

删除堆顶的数据

将头结点和尾结点数据交换 然后size--,再向下调整。

AdjustDown(HPDataType* a, size_t size, size_t root)
{
	size_t parent = root;
	size_t child = parent * 2 + 1;
	//
	while (child < size)
	{
		//找出孩子中较小的那一个,注意完全二叉树可能不存在右孩子
		//确定左右子树谁的值更小
		if (a[child] > a[child + 1] && child + 1 < size)
		{
			//默认是左<右,这里是判断调整
			child++;
		}
		//如果孩子小于父亲就交换
		if (a[child] < a[parent])
		{
			Swap(&a[parent], &a[child]);
		}
		else
		{
			break;
		}
		//继续向下调整
		parent = child;
		child = parent * 2 + 1;
	}
}
void HPPop(HP* php)
{
	//将堆顶的数据和堆尾的数据交换位置,再向下调整,恢复堆
	assert(php);
	//保证堆不为空
	assert(php->size > 0);
	//交换位置
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	//向下调整
	AdjustDown(php->a, php->size, 0);
}

判断堆是否为空

size指向数组下一位 如果为空则是空

bool HPEmpty(HP* php)
{
	assert(php);
	//用表达式的返回值来判断,为0就为空
	return php->size == 0;
}

返回栈顶的值

size_t HPSize(HP* php)
{
	assert(php);
	//根据数组的性质,可直接返回size的值
	return php->size;
}

堆的大小

直接用size的值

HPDataType HPTop(HP* php)
{
	assert(php);
	//堆不为空
	assert(php->size > 0);
 
	return php->a[0];
}

堆排序

升序用大堆,降序用小堆。

以大堆为例

1.构造大堆,数组最大值就是根节点

2.顶端数与末尾数交换

3.反复执行2.

建造大堆:

首先将无序数组看做堆结构,按照综上到下,从左到右依次填入二叉树中。 

从最后一个非叶子结点即6,比较她左右节点较大值如果比6大就交换位置。

例如这里6和9需要交换。 

 找到下一个非叶子节点4重复上述步骤

 如此重复操作得到大堆 接下来进行排序

堆排序算法步骤

1.把无序数组构造成二叉树堆(以大堆为例)。

2.堆顶就是序列最大值,将堆顶与末尾元素交换,此时末尾就是最大值。

3.将剩余n-1个元素重新构造成一个堆,即重复1,2.

如此得到有序序列

堆排序不稳定

空间复杂度为O(1)

平均的时间复杂度为O(nlogn)

最坏情况下也稳定在O(nlogn) 

void HeapAdjust(int* arr, int start, int end)
{
	int tmp = arr[start];
	for (int i = 2 * start + 1; i <= end; i = i * 2 + 1)
	{
		if (i < end&& arr[i] < arr[i + 1])//有右孩子并且左孩子小于右孩子
		{
			i++;
		}//i一定是左右孩子的最大值
		if (arr[i] > tmp)
		{
			arr[start] = arr[i];
			start = i;
		}
		else
		{
			break;
		}
	}
	arr[start] = tmp;
}
void HeapSort(int* arr, int len)
{
	//第一次建立大根堆,从后往前依次调整
	for(int i=(len-1-1)/2;i>=0;i--)
	{
		HeapAdjust(arr, i, len - 1);
	}
	//每次将根和待排序的最后一次交换,然后在调整
	int tmp;
	for (int i = 0; i < len - 1; i++)
	{
		tmp = arr[0];
		arr[0] = arr[len - 1-i];
		arr[len - 1 - i] = tmp;
		HeapAdjust(arr, 0, len - 1-i- 1);
	}
}
int main()
{
	int arr[] = { 9,5,6,3,5,3,1,0,96,66 };
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
	printf("排序后为:");
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

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

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

相关文章

【华为OD机试模拟题】用 C++ 实现 - 吃火锅(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

【华为OD机试模拟题】用 C++ 实现 - 分积木(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

基于博客系统的测试用例

登陆界面博客预览页博客详情页博客编辑页

每日一题——L1-085 试试手气(15)

L1-085 试试手气 我们知道一个骰子有 6 个面&#xff0c;分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态&#xff0c;即它们朝上一面的点数&#xff0c;让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙&#xff0c;每次摇出的结果都满足以下两个条件&#xff1a;…

【Java8】

1、接口中默认方法修饰为普通方法 在jdk8之前&#xff0c;interface之中可以定义变量和方法&#xff0c;变量必须是public、static、final的&#xff0c;方法必须是public、abstract的&#xff0c;由于这些修饰符都是默认的。 接口定义方法: public抽象方法需要子类实现 接口定…

TCP报文详解

目录 &#x1f407;今日良言:但尽全力,且让心安 &#x1f43c;一、TCP协议特点 &#x1f433;二、TCP协议段格式 &#x1f42f;三、TCP的10个核心机制 &#x1f41d;四、三次握手和四次挥手 &#x1f407;今日良言:但尽全力,且让心安 &#x1f43c;一、TCP协议特点 TCP :Tr…

OAuth 2.0 认证和攻击面

0x00 前提 最近在测试公司的 oauth 认证方面的问题&#xff0c;要再去熟悉一下这块&#xff0c;所以把这块写一下。 0x01 OAuth2.0 概念 OAuth是一个关于授权&#xff08;authorization&#xff09;的开放网络标准&#xff0c;目前是最常见最通用的一个授权协议。 什么地方…

uni-app:获取当前经纬度解决方案+如何布置全局组件

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 一.布置全局组件 在我们开发的过程中&#xff0c;会碰到一个现象&#xff0c;就是在页面里面引入组件&#xff0c;总算要写import&#xff0c;components才能引用&#xff0c;这里给大家分享我们的一个…

JavaWeb--Tomcat

Tomcat1 简介1.1 什么是Web服务器2 基本使用2.1 下载2.2 安装2.3 卸载2.4 启动2.5 关闭2.6 配置2.7 部署3 Maven创建Web项目3.1 Web项目结构3.2 创建Maven Web项目4 IDEA使用Tomcat4.1 集成本地Tomcat4.2 Tomcat Maven插件目标&#xff1a; 掌握Tomcat的使用掌握在IDEA中使用To…

CMake模块的使用和自定义模块

CMake模块的使用和自定义模块一、前言二、使用Find模块2.1、准备工作2.2、添加头文件路径和库文件2.3、< name >_FOUND 来控制工程特性三、编写自定义的Find模块3.1、 准备工作3.2、cmake 模块3.3、使用自定义的FindHELLO 模块构建工程3.4、如果没有找到hello library四、…

备战金三银四,熬夜半个月汇集大厂 Java 岗 1600 页面试真题

如果你不停地加班。却很少冒险&#xff0c;也很少学习&#xff0c;那你极大可能会陷入到内卷中。 为什么这么说呢&#xff1f;我们先来捋清楚「内卷」的概念&#xff1a; 「内卷化」简而言之就是&#xff1a;日复一日&#xff0c;越混越掉坑里。 所谓内卷化&#xff0c;指一种…

CHAPTER 2 Web Server - nginx 功能示例

nginx功能示例2.1 Nginx反向代理-示例1. 配置nginx.conf2. 配置访问机器的hosts3. 访问网址4. 遗留问题2.2 Nginx负载均衡-详解及示例2.2.1 负载均衡配置参数简介1. upstream模块简介2. 负载均衡算法简介2.2.2 示例演示1. 修改配置文件2. 示例效果2.3 Nginx动静分离-示例1. 修改…

【华为OD机试模拟题】用 C++ 实现 - 任务调度(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 货币单位换算(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 选座位(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 停车场最大距离(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 重组字符串(2023.Q1) 【华为OD机试模…

【电路设计】常见电路及相关解释

前言 在接触电路设计过程中&#xff0c;往往需要用到一些常见的电路&#xff0c;但是临时查找又太浪费时间&#xff0c;因此&#xff0c;想总结一些常见电路的分析方式。 1 RC电路充放电公式 一般的RC电路如下图所示。 其充放电公式如下所示。 VtV0(V1−V0)(1−e−tRC)tRCln…

Python---关联与继承

专栏&#xff1a;python 个人主页&#xff1a;HaiFan. 专栏简介&#xff1a;Python在学&#xff0c;希望能够得到各位的支持&#xff01;&#xff01;&#xff01; 关联与继承前言has a关联关系is a继承关系子类不添加__init__子类添加__init__前言 has a关联关系 has - a 是在…

【华为OD机试模拟题】用 C++ 实现 - 符合条件的子串长度(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

28张图讲解支付系统的通用设计,漂亮!

支付永远是一个公司的核心领域&#xff0c;因为这是一个有交易属性公司的命脉。那么&#xff0c;支付系统到底长什么样&#xff0c;又是怎么运行交互的呢&#xff1f;抛开带有支付牌照的金融公司的支付架构&#xff0c;下述链路和系统组成基本上符合绝大多数支付场景。其实整体…

HCIA-HarmonyOS Application Developer——题目集1

题目1 1、一位开发人员在设计应用程序时&#xff0c;添加了一个Text组件和Button组件&#xff0c;开发样图如下所示。该开发者不能选择哪种布局方式来放置组件? A、StackLayout B、DependentLayout C、DirectionalLayout D、TableLayout 解析&#xff1a;&#xff08;A&#…

物理机与启动的Docker容器间的目录映射

第一步&#xff0c;进入宿主机的配置文件目录。 # 查看容器存放目录 命令&#xff1a;docker info | grep Root # 得到容器id 命令&#xff1a;cd /var/lib/docker/containers # 进入配置文件目录 命令&#xff1a;cd /var/lib/docker/containers/容器id 第二步&#xf…

【vue2小知识】实现axios的二次封装

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;在vue2中实现axios的二次封装 目录 一、平常axios的请求发送方式 二、axios的一次封装…