二叉树-堆

news2024/11/23 10:49:10

树的几个重要定义

1.树=根+子树=根+亲缘关系
2.节点的度:有几个子树或根有几个孩子
3.叶子节点:没有孩子的终端节点 度为0
4.分支节点:度不为0的节点
5.树=叶子+分支节点
6.父亲节点/双亲节点
7.子节点
8.树的度:最大节点的度就是树的度
9.树的层:一般从第一层开始数,也有从0层开始数的,但是多数情况下从第一层开始
10.树的高/深度:一共多少层
11.空树的度:0
为什么会有0层这个少数概念?
数组我们是从下标为0开始的
为什么呢—>为了方便计算
我们都是知道 数组名=首元素地址

a[i]=*(a+i);

数组从零开始就是为了方便计算

12.森林:多颗互不相交的树----->并查集

树是由递归定义的:任何一棵树=[根+N颗子树(N>=0)]

注意:树的子树之间是不相交的
若子树相交则为—>图

一颗有N个节点的数有N-1条边

树给如何代码定义呢?

这里循序渐进的介绍三种方法,其中最后一种是最绝妙最常用的方法
(1).

//1.明确度 N=4
#define N 4
struct TreeNode
{
	int val;
	struct TreeNode* sub[N];//指针数组
};

(2).

//2.未明确度
SeqList subs;//顺序表内部存struct TreeNode* 在C语言就有些麻烦
//C++中有 vector<struct TreeNode*>suns;

(3).

//3.左孩子右兄弟法
struct TreeNdoe
{
	int val;
	struct TreeNode* leftchild;
	struct TreeNode* rightbrother;
};
/*
不管我有几个孩子
我都只想左边第一个孩子 
child 指向左孩子
brother指向兄弟
*/

在这里插入图片描述
这是树的定义
在树的结构中我们最常用的是二叉树

二叉树的定义就只有左孩子和右孩子,他至多两个孩子,不存在多个兄弟

二叉树:满二叉树 和 完全二叉树

满二叉树:高度为H ,一共有2^H-1个节点

完全二叉树:前H-1层都是满的,最后一层不满,但从左到右必须连续存在
节点个数范围:2^H~2 ^H-1

所以满二叉树是特殊的完全二叉树

二叉树是能存非常多的节点的

假设有N个节点
2^H-1=N
H=log(N)+1

H=20 能存100W+个节点
H=30 能存10亿+个节点

二叉树的存储—数组

假设父亲在数组的下标是i
左孩子=2i+1
右孩子=2
i+2

假设孩子在数组的下标是j
需要判断孩子是左孩子还是有孩子吗---->不用判断
除法运算直接取整
父亲=(j-1)/2

关于数组的存储方式是只适用于完全二叉树的
非完全二叉树倒是也能用就是不适合
非完全二叉树通常用链式结构存储

1.堆是一个完全二叉树----->数组存储
2.大堆:任何一个父亲都大于等于孩子
小堆:任何一个父亲都小于等于孩子

注意:大堆小堆都不是严格的升序降序,因为孩子之间并无大小关系

但是小堆的根是最小的,大堆的根是最大的

堆在逻辑上:是一棵树
物理上:是一个数组

定义堆的代码
Heap.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;
//本质上是数组,一个指针 一个数组大小 一个有效空间大小

//接口
void HPInit(HP* php);
void HPDestroy(HP* php);
void HPPush(HP* php,HPDataType x);
void HPPop(HP* php);

Heap.c

#include"Heap.h"
void HPInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
}

void HPDestroy(HP*php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType* tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//向上调整法  谁小谁当爹
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 HPPush(HP* php,HPDataType x)
{
	//利用向上调整法 插到堆尾
	//根据是大堆小堆 与父亲比较调整位置
	assert(php);
	//先看看有没有空间插入
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		//原来空间就为0先给4个,原来有空间现在没地方插直接扩2倍
		HPDataType* tmp = (HPDataType*)realloc(php->a,newcapacity * sizeof(HPDataType));
	
	//判断扩容成功与否
	if (tmp = NULL)
	{
		perror("realloc fail");
		return;
	}
	php->a = tmp;
	php->capacity = newcapacity;
	}
	//x插到堆尾
	php->a[php->size] = x;
	php->size++;
	Adjustup(php->a, php->size - 1);//把堆尾元素当做孩子与父亲比较进行位置调整
}

以上就只有插入及插入所需要的向上调整算法

通过一个数组实现堆:

#include"Heap.h"
void TestHeap01()
{
	int a[] = { 4,2,8,1,5,6,7,9 };
	HP hp;
	HPInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HPPush(&hp, a[i]);//插入并及时调整位置
	}
}

向下调整算法

//向下调整算法
void Adjustdown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//n就是数组大小
	//向上调整找父亲,向下调整找孩子
	//找那个孩子呢? 假设法假设左孩子小,找左孩子
		
		//判断下到底是哪个孩子小
		if (child + 1 < n && a[child + 1] < a[child])
			//if (a[child + 1] < a[child]) 这样有溢出风险
		{
			++child;//右孩子小,那就把孩子的值定为右孩子
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

删除

void HPPop(HP* php)
{
	/*
	将堆顶与堆尾互换,删除堆尾,再利用向下调整算法调整位置
	*/
	assert(php);
	assert(php->size > 0);
	Sawp(&php->a[0], &php->a[php->size - 1]);//顶尾交换
	//删除尾部就很简单直接--
	php->size--;
	Adjustdown(php->a, php->size, 0);//从堆顶一个一个向下比较调整
}

注意:在这里我们得到的都是小堆

实现堆:是由数组一个一个的插入(插入中包含向上调整算法)

我们要控制得到的是大堆还是小堆:
可以通过控制两个调整算法的判断比较条件来实现

以上示例只能怪都是<号
若想得到大堆就改成>号

注意:若想使用向下调整,左右子树必须是小堆

返回堆顶元素

HPDataType HPTop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

判空

bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

Push尾插 利用向上调整法
Pop尾删 利用向下调整法

实现一个打印有序(并不是严格的排序)

1.实现一个堆
2.因为通过调整算法后一定是有序的
所以打印顶,再删除顶,在继续打印出来就一定是有序的
但这并不是堆排序

int main()
{
	int a[] = { 4,2,8,1,5,6,9,7 };
	HP hp;
	HPInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HPPush(&hp, a[i]);//插入并及时调整位置
	}
	while (!HPEmpty)
	{
		printf("%d", HPTop(&hp));
		HPPop(&hp);
	}
	return 0;
}

注意:这只是打印出来是有序的,同样到底想升序还是降序去改变两种调整算法的判断条件

Top K----->相同的逻辑
寻找最大的前K个

int main()
{
	int a[] = { 4,2,8,1,5,6,9,7 };
		HP hp;
		HPInit(&hp);
		for (int i = 0; i < sizeof(a) / sizeof(int); i++)
		{
			HPPush(&hp, a[i]);//插入并及时调整位置
		}
	int k;
	scanf("%d", &k);
	while (k--)
	{
		printf("%d", HPTop(&hp));
		HPPop(&hp);
	}
	return 0;
}

这个算法的时间复杂度:log(N)
算是很快的算法
10亿个数据 只需要调30次

前面我们只是实现了打印有序,并未让数组变为有序

接下来的代码我们将让数组a变为有序数组

int main()
{
	int a[] = { 4,2,8,1,5,6,9,7 };
	HP hp;
			HPInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HPPush(&hp, a[i]);//插入并及时调整位置
	}
	int i = 0;
	while (!HPEmpty)
	{
		a[i++] = HPTop(&hp);//直接把顶放进数组中
		HPPop(&hp);
		
	}

	//出循环就整个数组都是有序的了
	return 0;
}

如何建堆

向上调整法建堆
时间复杂度:O(N*logN)

void HeapSort(int *a,int n)
{
	for (int i = 1; i < n; i++)
	{
		Adjustup(a, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		Adjustdown(a, end, 0);
		--end;
	}
}

向下调整法建堆
时间复杂度:O(N)
从最后一个分支节点开始调
也就是最后一个叶子的父亲

一个子树一个子树的调

4 2 8 1 5 6 9 7 2 7 9
最后一个分支节点是5
从5的位置开始–,像前面依次调整位置

void HeapSort(int* a, int n)
{
	for (int i = (n-1-1)/2; i >=0; i--)
	{
		Adjustdown(a,n,i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		Adjustdown(a, end, 0);
		--end;
	}
}

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

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

相关文章

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪BD311R 发布时间: 2024-10-23 11:28:42 一、 产品图片&#xff1a; 二、 产品特性&#xff1a; 4G性能&#xff1a;支持2K超高清图传&#xff0c;数据传输不掉帧&#xff0c;更稳定。 独立北…

浮动路由:实现出口线路的负载均衡冗余备份。

浮动路由 Tip&#xff1a;浮动路由指在多条默认路由基础上加入优先级参数&#xff0c;实现出口线路冗余备份。 ip routing-table //查看路由表命令 路由优先级参数&#xff1a;越小越优 本次实验测试两条默认路由&#xff0c;其中一条默认路由添加优先级参数&#xff0c;设置…

ssm077铁岭河医院医患管理系统+vue(论文+源码)_kaic

毕业设计&#xff08;论文) 题 目&#xff1a; 医院医患管理系统 姓 名&#xff1a; 学 号&#xff1a; 所属学院&#xff1a; 专业班级&#xff1a; 指导&#xff1a; 职 称&#xff1a; 完成日期 2021年 月 摘 要 21世纪的今天&#xf…

关于在VS中使用Qt不同版本报错的问题

最开始需要配置的地方 首先看一下我的Qt有关的环境变量&#xff1a; Path环境变量里&#xff1a; 这里就是把对应Qt编译器环境下的bin目录放进来&#xff1a;比如你使用的是msvc2017_64或者MinGW QMAKESPEC环境变量&#xff1a; 这个就选择Qt对应的编译器目录下的\mkspecs\w…

Redis 权限控制(ACL)|ACL 命令详解、ACL 持久化

官网文档地址&#xff1a;https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/ 使用版本&#xff1a;Redis7.4.1 什么是 ACL&#xff1f; ACL&#xff08;Access Control List&#xff09;&#xff0c;权限控制列表&#xff0c;是 Redis 提供的一种…

任务中心全新升级,新增分享接口文档功能,MeterSphere开源持续测试工具v3.4版本发布

2024年11月5日&#xff0c;MeterSphere开源持续测试工具正式发布v3.4版本。 在这一版本中&#xff0c;系统设置方面&#xff0c;任务中心支持实时查看系统即时任务与系统后台任务&#xff1b;接口测试方面&#xff0c;新增接口文档分享功能、接口场景导入导出功能&#xff0c;…

GEE 数据集——美国gNATSGO(网格化国家土壤调查地理数据库)完整覆盖了美国所有地区和岛屿领土的最佳可用土壤信息

目录 简介 代码 引用 网址推荐 知识星球 机器学习 gNATSGO&#xff08;网格化国家土壤调查地理数据库&#xff09; 简介 gNATSGO&#xff08;网格化国家土壤调查地理数据库&#xff09;数据库是一个综合数据库&#xff0c;完整覆盖了美国所有地区和岛屿领土的最佳可用土…

3.PyCharm工具

第三方IDE&#xff0c;集成开发工具&#xff0c;官网下载。 社区版本&#xff0c;免费使用。 创建项目

Rust移动开发:Rust在iOS端集成使用介绍

iOS调用Rust 上篇介绍了 Rust移动开发&#xff1a;Rust在Android端集成使用介绍, 这篇主要看下iOS上如何使用Rust&#xff0c;Rust可以给移动端开发提供跨平台&#xff0c;通用组件支持。 该篇适合对iOS、Rust了解&#xff0c;想知道如何整合调用和编译的&#xff0c;如果想要…

video素材格式转换--mp4转webm(vue3+Nodejs)

总体实现使用ffmpeg 自动化demo实现 vue3Nodejsffmpeg 一、官网下载ffmpeg https://ffmpeg.org/ 1-1选择对应系统下载 1-2下载完成后配置环境变量 1-2-1将下载文件的bin目录配置到环境变量中 例如:D:\ffmpeg\bin 1-3测试ffmpeg是否安装成功 ffmpeg -version 如图 证明安装成…

YOLOPv2论文翻译

YOLOPv2: Better, Faster, Stronger for Panoptic Driving Perception 摘要 在过去的十年中&#xff0c;多任务学习方法在解决全景驾驶感知问题方面取得了令人鼓舞的成果&#xff0c;既提供了高精度又具备高效能的性能。在设计用于实时实际自动驾驶系统的网络时&#xff0c;这…

Golang | Leetcode Golang题解之第553题最优除法

题目&#xff1a; 题解&#xff1a; func optimalDivision(nums []int) string {n : len(nums)if n 1 {return strconv.Itoa(nums[0])}if n 2 {return fmt.Sprintf("%d/%d", nums[0], nums[1])}ans : &strings.Builder{}ans.WriteString(fmt.Sprintf("%d…

基于LORA的一主多从监测系统_实物展示

提供&#xff1a;成品硬件 4G模块 详细开发流程 源码 原理图 主节点和子节点A的合照来一张 主节点 子节点A

教程:FFmpeg结合GPU实现720p至4K视频转换

将一个 720p 的视频放大编码到 4K&#xff0c;这样的视频处理在很多业务场景中都会用到。很多视频社交、短视频、视频点播等应用&#xff0c;都会需要通过服务器来处理大量的视频编辑需求。 本文我们会探讨一下做这样的视频处理&#xff0c;最低的 GPU 指标应该是多少。利用开源…

css | padding vs margin

前置知识 height是作用域内容(content)区域的 padding和margin用百分比的时候是怎么算的&#xff1f;父元素的宽度。注意&#xff0c;不是根据父元素相应的属性&#xff0c;就是父亲的width 自身的height是0 以下代码&#xff0c;外面盒子是100x10的&#xff0c;里面的widt…

监控架构- Grafana-监控大屏

1. Grafana极速上手指南 1.1 环境准备 主机ip地址grafana10.0.0.66zabbix_server10.0.0.62 1.2 部署grafana 9.3.6 ##去官网找rpm包下载并上传 ## 安装 yum localinstall -y grafana-9.3.6-1.x86_64.rpm## 启动服务并设置开机自启动 systemctl enable --now grafana-server…

数据分析反馈:提升决策质量的关键指南

内容概要 在当今快节奏的商业环境中&#xff0c;数据分析与反馈已成为提升决策质量的重要工具。数据分析不仅能为企业提供全面的市场洞察&#xff0c;还能帮助管理层深入了解客户需求与行为模式。掌握数据收集的有效策略和工具&#xff0c;企业能够确保获得准确且相关的信息&a…

SpringBoot助力的共享汽车业务优化系统

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

【启程Golang之旅】从零开始构建可扩展的微服务架构

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

多个NVR同时管理EasyNVR多品牌NVR管理工具/设备:IP常见问题解决方案

随着视频监控技术的不断发展&#xff0c;NVR&#xff08;网络视频录像机&#xff09;已经成为现代安防系统的重要组成部分。而为了更高效地管理多个品牌的NVR设备&#xff0c;EasyNVR这一多品牌NVR管理工具应运而生。然而&#xff0c;在实际使用过程中&#xff0c;尤其是在多个…