数据结构:详解【树和二叉树】

news2024/11/18 20:21:02

1. 树的概念及结构(了解)

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

1.2 树的结构
在这里插入图片描述

1.3 树与非树

在这里插入图片描述

1.4 树在实际中的运用(表示文件系统的目录树结构)

在这里插入图片描述

2. 与树的结构相关的概念

在这里插入图片描述
在这里插入图片描述

  • 节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6。
  • 叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I…等节点为叶节点。
  • 非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点。
  • 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点。
  • 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点。
  • 兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点。
  • 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6。
  • 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推
  • 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4。
  • 森林:由m(m>0)棵互不相交的多颗树的集合称为森林;(数据结构中的学习并查集本质就是一个森林)。

3. 二叉树的概念及结构

2.1 概念
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树右子树的二叉树组成。

2.2 二叉树的特点:
1.每个结点最多有两棵子树,即二叉树不存在度大于2的结点
2.二叉树的子树有左右之分,其子树的次序不能颠倒

2.3 两种特殊的二叉树
(1)满二叉树:
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是2k -1 ,则它就是满二叉树。
(2)完全二叉树:
对于深度为K的,有n个结点的二叉树,如果满足前K-1层都是满的,最后一层不满,但最后一层从左到右都是连续的。则这个二叉树就是完全二叉树。
在这里插入图片描述

(3)对这两种二叉树的有关数据的推导

在这里插入图片描述

4. 二叉树的性质

  • 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点
  • 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h- 1
  • 对任何一棵二叉树, 如果度为0其叶结点个数为 n0, 度为2的分支结点个数为 n2,则有n0=n2+1
  • 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h = logN(以2为底)。

5. 二叉树的存储

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

在这里插入图片描述

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

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c24bc02ae45b457aba2121bb692246bc.png

6. 二叉树的前,中,后序遍历

要实现前,中,后序遍历,我们需要再来理解二叉树的结构。把任一一棵二叉树分为三部分:根节点,左子树,右子树。

我们这里先拿一棵简单的二叉树举例:
在这里插入图片描述

6.1 二叉树的前序(先根)遍历:
根,左子树,右子树
对应上图为:A B D NULL NULL E NULL NULL C NULL NULL。

6.2 二叉树的中序(中根)遍历:
左子树,根,右子树
对应上图为:NULL D NULL B NULL E NULL A NULL C NULL。

6.3 二叉树的后序(后根)遍历:
左子树,右子树,根
对应上图为:NULL NULL D NULL NULL E B NULL NULL C A。

7. 有关二叉树的常用功能的实现

7.1 三序(深度优先)遍历的代码实现

这里我们需要用到分治算法: 分而治之,把大问题分成类似的子问题,子问题再分成子问题……直到子问题不可再分割。实际上就是递归思想

7.2 根据上图代码实现如下:

#define _CRT_SECURE_NO_WARNINGS 

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

typedef char BTDataType;

//定义二叉树的结构
typedef struct BinaryTreeNode
{
	BTDataType data;//存放的数据
	struct BinaryTreeNode* left;//左子树
	struct BinaryTreeNode* right;//右子树
}BTNode;


//前序遍历
void PrevOrder(BTNode* root)//根节点
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	printf("%c ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}


//中序遍历
void InOrder(BTNode* root)//根节点
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);

}


//后序遍历
void PostOrder(BTNode* root)//根节点
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->data);

}

void TreeTest()
{

	//1.开辟节点和初始化
	BTNode* A = (BTNode*)malloc(sizeof(BTDataType));
	if (A == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	A->data = 'A';
	A->left = NULL;
	A->right = NULL;

	BTNode* B = (BTNode*)malloc(sizeof(BTDataType));
	if (B == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	B->data = 'B';
	B->left = NULL;
	B->right = NULL;

	BTNode* C = (BTNode*)malloc(sizeof(BTDataType));
	if (C == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	C->data = 'C';
	C->left = NULL;
	C->right = NULL;

	BTNode* D = (BTNode*)malloc(sizeof(BTDataType));
	if (D == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	D->data = 'D';
	D->left = NULL;
	D->right = NULL;

	BTNode* E = (BTNode*)malloc(sizeof(BTDataType));
	if (E == NULL)
	{
		perror("malloc fail\n");
		return;
	}
	E->data = 'E';
	E->left = NULL;
	E->right = NULL;

	//2.链接各个节点
	A->left = B;
	A->right = C;
	B->left = D;
	B->right = E;

	//3.进行输出
	PrevOrder(A);
	printf("\n");

	InOrder(A);
	printf("\n");

	PostOrder(A);
	printf("\n");
}

int main()
{

	TreeTest();

	return 0;
}

输出结果与我们分析的相同:

在这里插入图片描述

7.22 前序函数递归展开图:
![![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/e81c18c342764d33a3d4497b7a349d03.png](https://img-blog.csdnimg.cn/direct/5021db310f0b46a5a506abe96959af6d.png
中序和后续的递归展开图类似,读者自行分析。

7.3 计算一棵二叉树的总节点数

方法 1:遍历递归计数,定义局部变量size,传地址计数

代码实现如下:


void TreeSize(BTNode* root,int *psize)
{
	if (root == NULL)
	{
		return;
	}
	else
	{
		(*psize)++;
	}

	TreeSize(root->left, psize);
	TreeSize(root->right, psize);

}

void TreeTest()
{
     ......//续上上文的代码和图
     
	int Asize = 0;
	TreeSize(A, &Asize);
	printf("Asize:%d\n", Asize);
	
	int Bsize = 0;
	TreeSize(B, &Bsize);
	printf("Bsize:%d\n", Bsize);
	
}

方法2:分治思想,递归

代码实现如下:

int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

void TreeTest()
{
     ......//续上上文的代码和图
     
	printf("Asize:%d\n",TreeSize(A) );
	
	printf("Bsize:%d\n",TreeSize(B) );
	
}

递归调用可抽象为:

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/3b543b40b6fe42139d9ea36bc59e7b5d.png

两种方法的输出结果均是:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c6d745f809604d9ba7e3a7d4f23cc8ca.png
7.4 计算一棵二叉树中叶子节点的个数
利用分治思想,后序遍历。

代码实现如下:

int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
    
    //是叶节点
	if (root->left == NULL && root->right == NULL)
		return 1;
		
    //左边的叶节点+右边的叶节点
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

void TreeTest()
{
     ......//续上上文的代码和图
	
	printf("LeafSize:%d\n",TreeLeafSize(A) );
}

输出结果是:
在这里插入图片描述

7.5 计算二叉树的最大深度

利用分治思想,后序遍历,当根节点为NULL时,返回0当根节点不为NULL时,分解子问题,先求左右子树的深度,该节点的深度 = 左右子树更大的那一个+1

代码实现如下:

int MaxDepth(BTNode* root)
{
	if (root == NULL)
		return 0 ;

	int leftdepth = MaxDepth(root->left);
	int rightdepth = MaxDepth(root->right);

	return leftdepth > rightdepth ? leftdepth + 1 : rightdepth + 1;

}

void TreeTest()
{
     ......//续上上文的代码和图
	
	printf("MaxDepth:%d\n",MaxDepth(A) );
}

输出结果是:

在这里插入图片描述
7.6 销毁二叉树
销毁二叉树不能从根节点开始销毁,不然会找不到其他节点。要用后序遍历,先左节点,右节点,最后根节点。

代码实现如下:

void DestoryTree(BTNode* root)
{
	if (root == NULL)
		return;

	DestoryTree(root->left);
	DestoryTree(root->right);

	free(root);
	root = NULL;
}

8. 二叉树的层序(广度优先)遍历

8.1 什么是层序遍历

设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

在这里插入图片描述

8.2 层序遍历的代码实现

要实现二叉树的层序遍历,我们需要借助队列先进先出的特性。其核心思想是:上一层的一个节点出的时候带其下一层的子节点进

画图解释如下:
在这里插入图片描述

代码实现如下:

void LealOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	if (root)
		QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);//取出队头
		QueuePop(&q);
		printf("%c ", front->data);

		if (front->left)//左不为空,入左节点
			QueuePush(&q, front->left);

		if (front->right)//右不为空,入右节点
			QueuePush(&q, front->right);
	}
	printf("\n");

	QueueDestory(&q);
}

void TreeTest()
{
     ......//续上上文的代码和图
	
	LealOrder(A);
}

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

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

相关文章

Vue项目登录页实现获取短信验证码的功能

之前我们写过不需要调后端接口就获取验证码的方法,具体看《无需后端接口,用原生js轻松实现验证码》这个文章。现在我们管理后台有个需求,就是登录页面需要获取验证码,用户可以输入验证码后进行登录。效果如下,当我点击获取验证码后能获取短信验证码: 这里在用户点击获取…

Cortex-M7 异常处理与返回

1 前言 当CM3开始响应一个中断时&#xff0c;会在它小小的体内奔涌起三股暗流&#xff1a;  入栈&#xff1a; 把8个寄存器的值压入栈;  取向量&#xff1a;从向量表中找出对应的服务程序入口地址;  选择堆栈指针MSP/PSP&#xff0c;更新堆栈指针…

LeetCode 19.删除链表的倒数第N个结点

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#x…

Leetcode 39.组合总和

题目 思路 1.确定递归函数的返回值及参数&#xff1a; 返回值是void,参数这里还是先设定两个全局变量。一个是path存放符合条件单一结果。如&#xff1a;&#xff08;1&#xff0c;2&#xff09;。一个是result&#xff0c;是所有path的集合[(1,2),(1,3)…]。 此外再设定一个…

前端学习之DOM编程-docmument对象、操作DOM对像内容、操作DOM对象属性方式、操作DOM对象的样式

docmument对象 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>document对象</title> </head> <body><div id"container" nameparent><ul name"parent&qu…

计算机系统结构速成,期末和自考必备

【拯救者】计算机系统结构速成(期末自考)均可用 1️⃣先讲每章对应的基础 2️⃣接着会讲对应的题目巩固 &#x1f357;提供文档下载 这里讲的是【 &#x1f337;速成&#x1f337; 速成&#x1f337; 速成】版本&#xff0c;按课本章节来&#xff0c; 抽取重点&#xff0c;翻…

数据分析——数据规范化

数据规范化是数据分析中的一个重要步骤&#xff0c;其目的在于确保数据的一致性和可比性&#xff0c;提高数据质量和分析结果的准确性。以下是一些数据规范化的常见方法和技术&#xff1a; 数据清洗&#xff1a;此步骤主要清除数据中的重复项、空格、格式错误等&#xff0c;确…

Transformer Based Multi-view Network for Mammographic Image Classification

“C-Tk” means “Classification Token” 辅助信息 作者未提供代码

【python从入门到精通】-- 第四战:语句汇总

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

C++:函数重载和引用

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习C&#xff1a;函数重载和引用&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 文章目录 函数重载1.函数重载的概念为什么C支持函数重载 引用引用的概念引…

C++中发送HTTP请求的方式

一&#xff0c;简介 使用C编程发送HTTP请求通常需要使用第三方的HTTP库或框架。在C中&#xff0c;有几个受欢迎的HTTP库可供选择&#xff0c;例如Curl、Boost.Beast和cpp-httplib。另外&#xff0c;也可以自己实现socket来发送http请求 二、使用Curl库发送HTTP请求 1. 确认当…

day60 动态规划part17

这两题看了自己写的笔记还不懂的话&#xff0c;看看这个up的思路就行&#xff1a; https://space.bilibili.com/111062940/search/video?keyword%E5%9B%9E%E6%96%87 647. 回文子串 中等 提示 给你一个字符串 s &#xff0c;请你统计并返回这个字符串中 回文子串 的数目。 回…

微带线特性阻抗快速计算---根据介质板参数和特性阻抗得到线宽(Matlab代码)

微带线特性阻抗快速计算—根据介质板参数和特性阻抗得到线宽&#xff08;Matlab代码&#xff09; 参考&#xff1a;https://blog.csdn.net/weixin_45811090/article/details/130045689 《射频电路理论与设计》第2版 黄玉兰著 《射频电路设计——理论与应用》第二版 Reinhold L…

STC89C51学习笔记(三)

STC89C51学习笔记&#xff08;三&#xff09; 综述&#xff1a;本文讲述了通过51单片机控制LED闪烁、流水灯、按键控制LED亮灭、按键控制LED实现二进制、按键控制LED左右移。 一、LED 1.LED闪烁 1&#xff09;原理 如果要实现LED闪烁&#xff0c;不可以直接先使LED亮&…

兼顾性能的数据倾斜处理方案

目录 前言 一、场景描述 二、常见的优化方法 2.1 Mapjoin 2.2 特殊值/空值打散 2.3 热点值打散&#xff0c;副表呈倍数扩散 2.4 热点数据单独处理/SkewJoin 2.5 方案总结 三、Distmapjoin 3.1 核心思路 3.2 代码实现 3.3 真实效果 四、方案总结 文章主要是介绍在支…

手把手教你从入门到精通C# MES通信

前言 我们在上位机软件开发的时候,经常需要与客户的MES系统进行通信,一般与MES系统通信需要实现的功能如下: 1、通过输入员工号来获取登录MES系统的权限 2、上传设备检测的OK/NG结果给MES系统; 3、上传设备生产过程中的异常信息给MES系统; 4、上传设备生产过程中的数据,…

(arxiv2401) CrossMAE

作者团队来自加州大学伯克利分校&#xff08;UC Berkeley&#xff09;和加州大学旧金山分校&#xff08;UCSF&#xff09;。论文主要探讨了在MAE的解码中&#xff0c;图像patch之间的依赖性&#xff0c;并提出了一种新的预训练框架 CrossMAE。 论文的主要贡献包括&#xff1a; …

【C++入门】关键字、命名空间以及输入输出

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

Ant Design Vue table固定列失效问题解决

问题描述&#xff1a;项目中封装好的公共table组件&#xff0c;基于Ant Design Vue table封装&#xff1b;使用中&#xff0c;用到了列固定&#xff0c;但是没生效&#xff0c;找了好久的原因。。。最后是因为外层容器标签导致&#xff1b; 解决方法&#xff1a;如果a-table组件…

Windows系统安装OpenSSH结合VS Code远程ssh连接Ubuntu【内网穿透】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-AwzyR2lkHKjD9HYl {font-family:"trebuchet ms",verdana,arial,sans-serif;f…