《数据结构:顺序实现二叉树》

news2024/11/24 8:30:27

文章目录

    • 一、树
        • 1、树的结构与概念
        • 2、树相关术语
    • 二、二叉树
        • 1、概念与结构
        • 2、满二叉树
        • 3、完全二叉树
    • 三、顺序二叉树存储结构
    • 四、实现顺序结构二叉树
        • 1、堆的概念与结构
        • 2、堆的实现
        • 3、堆的排序

一、树

1、树的结构与概念

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

  • 有一个特殊的结点,称为根结点,根结点没有前驱结点。
  • 除根结点外,其余结点被分成 M(M>0)个互不相交的集合,其中每个集合又是一颗结构与树类似的子树。每颗自树的根结点有且只有一个 前驱,可以有0个或多个后继。因此树是递归定义的。

在这里插入图片描述

树形结构中,⼦树之间不能有交集,否则就不是树形结构

非树形结构:
在这里插入图片描述

  • 子树是不相交的
  • 除根结点外,每个结点有且仅有一个父节点
  • 一颗N个结点的树有N - 1条边
2、树相关术语

在这里插入图片描述

  • ⽗结点/双亲结点:若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点; 如上图:A是B的⽗结点
  • ⼦结点/孩⼦结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点; 如上图:B是A的孩⼦结点
  • 结点的度:⼀个结点有⼏个孩⼦,他的度就是多少;⽐如A的度为6,F的度为2,K的度为0
  • 树的度:⼀棵树中,最⼤的结点的度称为树的度; 如上图:树的度为 6
  • 叶⼦结点/终端结点:度为 0 的结点称为叶结点; 如上图: B、C、H、I… 等结点为叶结点
  • 分⽀结点/⾮终端结点:度不为 0 的结点; 如上图: D、E、F、G… 等结点为分⽀结点
  • 分⽀结点/⾮终端结点:度不为 0 的结点; 如上图: D、E、F、G… 等结点为分⽀结点
  • 结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推;
  • 树的⾼度或深度:树中结点的最⼤层次; 如上图:树的⾼度为 4
  • 结点的祖先:从根到该结点所经分⽀上的所有结点;如上图: A 是所有结点的祖先
  • 路径:⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列;⽐如A到Q的路径为:A-E-J-Q;H到Q的路径H-D-A-E-J-Q
  • ⼦孙:以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。如上图:所有结点都是A的⼦孙
  • 森林:由 m(m>0) 棵互不相交的树的集合称为森林;

二、二叉树

1、概念与结构

树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。

在这里插入图片描述

二叉树具备以下特点:

  • 1.⼆叉树不存在度⼤于 2 的结点
    1. ⼆叉树的⼦树有左右之分,次序不能颠倒,因此⼆叉树是有序树

注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成的

在这里插入图片描述

2、满二叉树

⼀个⼆叉树,如果每⼀个层的结点数都达到最⼤值,则这个⼆叉树就是满⼆叉树。也就是说,如果⼀个⼆叉树的层数为 K ,且结点总数是 2k − 1 ,则它就是满⼆叉树。

在这里插入图片描述

3、完全二叉树

完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。对于深度为 K 的,有 n 个结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从 1 ⾄ n 的结点⼀⼀对应时称之为完全⼆叉树。要注意的是满⼆叉树是⼀种特殊的完全⼆叉树。

在这里插入图片描述

二叉树性质

  • 1)若规定根结点的层数为 1 ,则⼀棵⾮空⼆叉树的第i层上最多有 2i−1 个结点
  • 2)若规定根结点的层数为 1 ,则深度为 h 的⼆叉树的最⼤结点数是 2h − 1
  • 3)若规定根结点的层数为 1 ,具有 n 个结点的满⼆叉树的深度 h = log ⁡ 2 ( n + 1 ) \log_2 (n+1) log2(n+1) ( log以2为底, n+1 为对数)

三、顺序二叉树存储结构

顺序结构存储就是使⽤数组来存储,⼀般使⽤数组只适合表⽰完全⼆叉树,因为不是完全⼆叉树会有空间的浪费,完全⼆叉树更适合使⽤顺序结构存储。

在这里插入图片描述

现实中我们通常把堆(⼀种⼆叉树)使⽤顺序结构的数组来存储,需要注意的是这⾥的堆和操作系统虚拟进程地址空间中的堆是两回事,⼀个是数据结构,⼀个是操作系统中管理内存的⼀块区域分段。

四、实现顺序结构二叉树

⼀般堆使⽤顺序结构的数组来存储数据,堆是⼀种特殊的⼆叉树,具有⼆叉树的特性的同时,还具备其他的特性。

1、堆的概念与结构

如果有⼀个关键码的集合K={ k 0 , k 1 , ⋯   , k n − 1 k_0, k_1, \cdots, k_{n-1} k0,k1,,kn1,把它的所有元素按完全⼆叉树的顺序存储⽅式存储,在⼀个⼀维数组中,并满⾜: K i K_i Ki<= K 2 ∗ i + 1 K_{2*i+1} K2i+1,i = 0、1、2… ,则称为⼩堆(或⼤堆)。将根结点最⼤的堆叫做最⼤堆或⼤根堆,根结点最⼩的堆叫做最⼩堆或⼩根堆。

在这里插入图片描述

堆具有以下性质

  • 堆中某个结点的值总是不⼤于或不⼩于其⽗结点的值;
  • 堆总是⼀棵完全⼆叉树。

顺序二叉树性质

  • 对于具有 n 个结点的完全⼆叉树,如果按照从上⾄下从左⾄右的数组顺序对所有结点从0 开始编号,则对于序号为 i 的结点有:
    1. 若 i>0 , i 位置结点的双亲序号: (i-1)/2 ; i=0 , i 为根结点编号,⽆双亲结点
    1. 若 2i+1<n ,左孩⼦序号: 2i+1 , 2i+1>=n 否则⽆左孩⼦
    1. 若 2i+2<n ,右孩⼦序号: 2i+2 , 2i+2>=n 否则⽆右孩⼦
2、堆的实现

堆的底层结构为数组,因此定义堆的结构为:

#pragma once

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


typedef int HPDateType;

typedef struct Heap
{
	HPDateType* arr;
	int capacity;
	int size;
}HP;

//初始化
void HPInit(HP* php);

//销毁
void HPDesTroy(HP* php);

//堆尾插入数据
void HPPush(HP* php, HPDateType x);

//向上调整
void AdjustUp(HPDateType* arr, int child);

//删除堆顶数据
void HPPop(HP* php);

//向下调整
void AdjustDown(HPDateType* arr, int parent,int n);

//取堆顶数据
HPDateType HPTop(HP* php);

//判断堆是否为空
bool HPEmpty(HP* php);

堆的函数实现:

#include"Heap.h"

//初始化
void HPInit(HP* php)
{
	assert(php != NULL);
	php->arr = NULL;
	php->capacity = php->size = 0;
}

//销毁
void HPDesTroy(HP* php)
{
	assert(php != NULL);
	free(php->arr);
	php->arr = NULL;
	php->capacity = php->size;
}

//交换
void swap(HPDateType* x, HPDateType* y)
{
	HPDateType tmp = *x;
	*x = *y;
	*y = tmp;
}

//向上调整
void AdjustUp(HPDateType* arr, int child)
{
	assert(arr != NULL);
	int parent = (child - 1) / 2;
	while (arr[parent] > arr[child] && child > 0)
	{
		swap(&arr[parent], &arr[child]);
		child = parent;
		parent = (child - 1) / 2;
	}
}

//插入数据
void HPPush(HP* php, HPDateType x)
{
	assert(php != NULL);
	//判断空间够不够
	if (php->capacity == php->size)
	{
		//增容
		int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
		HPDateType* tmp = (HPDateType*)realloc(php->arr, newcapacity*sizeof(HPDateType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(1);
		}
		php->arr = tmp;
		tmp = NULL;
		php->capacity = newcapacity;
	}
	php->arr[php->size++] = x;
	AdjustUp(php->arr, php->size - 1);
}

//删除数据
void HPPop(HP* php)
{
	assert(php != NULL);
	assert(php->size > 0);
	swap(&php->arr[0], &php->arr[php->size - 1]);
	php->size--;
	AdjustDown(php->arr, 0,php->size);
}

//向下调整
void AdjustDown(HPDateType* arr, int parent,int n)
{
	assert(arr != NULL);
	int child = (parent * 2) + 1;
	while (child < n)
	{
		if (child + 1 < n && arr[child + 1] < arr[child])
		{
			child++;
		}
		if (arr[child] < arr[parent])
		{
			swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


//取堆顶数据
HPDateType HPTop(HP* php)
{
	assert(php != NULL);
	assert(php->size > 0);
	return php->arr[0];
}


//判断堆是否为空
bool HPEmpty(HP* php)
{
	assert(php != NULL);
	return php->size == 0;
}
3、堆的排序

运用堆排序时间复杂度大大减小

void HeapSort(int* arr, int n)
{
	//µ
	int i = 0;
	int parent = 0;
	int child = 0;
	for (i = (n - 1) / 2; i >= 0; i--)
	{
		parent = i;
		child = parent * 2 + 1;
		while (child < n)
		{
			if (child + 1 < n && arr[child + 1] < arr[child])
			{
				child++;
			}
			if (arr[child] < arr[parent])
			{
				int tmp = arr[child];
				arr[child] = arr[parent];
				arr[parent] = tmp;
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}

	for (i = n - 1; i > 0; i--)
	{
		parent = 0;
		child = i;
		int tmp = arr[child];
		arr[child] = arr[parent];
		arr[parent] = tmp;
		child = parent * 2 + 1;
		while (child < i)
		{
			if (child + 1 < i && arr[child + 1] < arr[child])
			{
				child++;
			}
			if (arr[child] < arr[parent])
			{
				tmp = arr[child];
				arr[child] = arr[parent];
				arr[parent] = tmp;
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}

	}
}

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

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

相关文章

选购指南:如何挑选最适合的快手矩阵系统

在短视频风潮席卷的今天&#xff0c;快手作为其中的佼佼者&#xff0c;吸引了无数创作者和商家的目光。然而&#xff0c;想要在快手上脱颖而出&#xff0c;仅凭内容和创意是远远不够的。一个强大且适合的快手矩阵系统&#xff0c;将是你通往成功的重要钥匙。那么&#xff0c;如…

『 Linux 』信号概念与信号的产生

文章目录 信号概念前台进程与后台进程信号的本质硬件理解信号的产生 信号概念 "信号"一词指用来传达信息或只是的各种形式的提示或标志; 在生活中常见的信号例如红绿灯,交通标志,短信通知等 在操作系统中,"信号"是一种用于异步通知进程发生特定事件的机制;…

【iOS】——SideTable

SideTable Side Table主要用于存储和管理对象的额外信息&#xff0c;特别是与弱引用相关的数据。Side Table的设计和使用是Objective-C运行时实现弱引用的基础&#xff0c;使得ARC&#xff08;Automatic Reference Counting&#xff09;能够正确地处理弱引用的生命周期。 新版…

【深度学习】大模型GLM-4-9B Chat ,微调与部署

下载好东西&#xff1a; 启动容器环境: docker run -it --gpus all --net host --shm-size8g -v /ssd/xiedong/glm-4-9b-xd:/ssd/xiedong/glm-4-9b-xd kevinchina/deeplearning:pytorch2.3.0-cuda12.1-cudnn8-devel-yolov8train bashpip install typer tiktoken numpy1.2…

2024最新版虚拟便携空调小程序源码 支持流量主切换空调型号

产品截图 部分源代码展示 urls.js Object.defineProperty(exports, "__esModule", {value: !0 }), exports.default ["9c5f1fa582bee88300ffb7e28dce8b68_3188_128_128.png", "E-116154b04e91de689fb1c4ae99266dff_960.svg", "573eee719…

web每日一练

每日一题 每天一题罢了。。 ctfshow内部赛签到 扫到备份文件 login.php <?php function check($arr){ if(preg_match("/load|and|or|\||\&|select|union|\|| |\\\|,|sleep|ascii/i",$arr)){echo "<script>alert(bad hacker!)</script>&q…

windows网页视频下载器+Video DownloadHelper+IDM+唧唧down

1:Video DownloadHelper 第一步:下载 链接&#xff1a;https://pan.baidu.com/s/1tWlXcJsq0kY_qrn9pzfCXw?pwdcsy2 提取码&#xff1a;csy2 --来自百度网盘超级会员V4的分享 第二步:浏览器扩展 以edge为例:点击管理扩展: 点击"加载解压缩的扩展": 选中我们的文…

中科亿海微信号采集核心板在振动采集场景中的应用

在工业现场控制领域&#xff0c;对于旋转物体的速度我们通用的做法是测量旋转所产生的振动量来倒推设备的转速值。振动采集系统是一种广泛用于检测和记录系统振动的设备&#xff0c;整体包括传感器和数据采集两部分。传感器类型包括加速度传感器、速度传感器和位移传感器&#…

微信小程序:多图片显示及图片点击放大,多视频显示

微信小程序&#xff1a;多图片显示及图片点击放大&#xff0c;多视频显示 01 多图片显示及图片点击放大02 多视频03 全部代码 01 多图片显示及图片点击放大 <view><view class"title">图片&#xff1a;</view><block wx:if"{{photoUrlList…

什么是离线语音识别芯片?与在线语音识别的区别

离线语音识别芯片是一种不需要联网和其他外部设备支持&#xff0c;‌上电即可使用的语音识别系统。‌它的应用场合相对单一&#xff0c;‌主要适用于智能家电、‌语音遥控器、‌智能玩具等&#xff0c;‌以及车载声控和一部分智能家居。‌离线语音识别芯片的特点包括小词汇量、…

【JavaEE】AQS原理

本文将介绍AQS的简单原理。 首先有个整体认识&#xff0c;全称是 AbstractQueuedSynchronizer&#xff0c;是阻塞式锁和相关的同步器工具的框架。常用的ReentrantLock、Semaphore、CountDownLatch等都有实现它。 本文参考&#xff1a; 深入理解AbstractQueuedSynchronizer只需…

2.5.LeNet

1.LeNet ​ LeNet-5由两个部分组成: 卷积编码器&#xff1a;由两个卷积层组成全连接层密集块&#xff1a;由三个全连接层组成 ​ 先试用卷积层来学习图片空间信息&#xff0c;然后使用全连接层来转换到类别空间 ​ 第一层卷积层要padding一下&#xff0c;收集边框的信息&…

数据清洗系统设计

设计一个高效的数据清洗系统旨在确保数据的质量&#xff0c;以便后续分析和决策过程可以基于准确、一致和完整的信息。以下是设计实时数据清洗系统时需要考虑的关键要素&#xff0c;结合之前提到的设计目标和原则&#xff1a; 1. 高效的数据处理 技术选型&#xff1a;采用并行…

git遇到OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0

最简单的方法&#xff0c;直接忽略SSL证书错误就好 一般是代理http/https或者其他问题导致的 直接输入 git config --global http.sslVerify "false" 即可

数学建模学习(2)——决策树

import pandas as pd from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score dfpd.read_excel(股票客户流失.xlsx) xdf.drop(columns是否流失)#x等于除是否流失这一列以外的数据…

layui+thymeleaf+jquery实现多图片,多视频的上传、预览、放大、编辑功能

layuithymeleafjquery实现多图片&#xff0c;多视频的上传、预览、放大、编辑功能 html: <!--多图片上传--> <div class"layui-row layui-col-space10"><div class"layui-form-item"><div class"layui-form-item layui-form-te…

证书上的服务器名错误解决方法

方法 win r &#xff0c;输入mmc 点击文件——>添加/删除管理单元 找到证书——> 添加 根据自己的存放选择存放位置 点击控制台根节点——> 受信任的根证书颁发机构——>导入 若还出现问题&#xff0c;则参考https://blog.csdn.net/mm120138687/article/details/…

【BUG】已解决:The above exception was the direct cause of the following exception:

The above exception was the direct cause of the following exception: 目录 The above exception was the direct cause of the following exception: 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c…

uniapp中出现Uncaught runtime errors

项目中运行出现上面的错误信息&#xff0c;使用uniapp发现&#xff0c;其实我只是跨域了&#xff0c;控制台报错&#xff0c;但是不想屏幕上显示&#xff1b; 解决办法是在vue.config.js增加如下配置即可 devServer: {client: {overlay: false,errors:true},}, 错误信息也不想…

求职学习day8

7/21回顾&#xff1a; 用面试鸭的意义可能就在于将知识点用问答的形式具象化在脑海&#xff0c;不然可能只停留在听说过的感觉 7.21 玩了一天。一个很不好的信号。今天下午要试试把 mall 项目的代码运行过一遍。 项目运行问题&#xff1a; 问题 1 &#xff1a;两个门服务器…