[C][数据结构][树]详细讲解

news2025/2/27 1:50:58

目录

  • 1.树的概念
  • 2.数的相关概念
  • 3.树的表示
  • 4.二叉树概念
  • 5.特殊的二叉树
  • 5.二叉树的性质
  • 6.二叉树的存储结构
    • 1.顺序结构
    • 2.链式结构
  • 7.链式结构二叉树
    • 1.二叉树的遍历 -- 深度优先遍历(DFS)
    • 2.二叉树的遍历 -- 广度优先遍历(DBS)
    • 3.接口实现


1.树的概念

  • 树是一种非线性的数据结构

    • 有一个特殊的结点,称为根结点,根节点没有前驱结点
    • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2……Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
    • 因此,树是递归定义的
  • 树形结构中,子树之间不能有交集,否则就不是树形结构

  • 任何一棵树都被分为根和子树
    请添加图片描述


2.数的相关概念

  • 节点的度一个节点含有的子树的个数称为该节点的度 - 如上图:A的为6
  • 叶节点度为0的节点称为叶节点 - 如上图:B、C、H、I…等节点为叶节点
  • 分支节点:度不为0的节点 - 如上图:D、E、F、G…等节点为分支节点
  • 父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点 - 如上图:A是B的父节点
  • 子节点:一个节点含有的子树的根节点称为该节点的子节点 - 如上图:B是A的孩子节点
  • 兄弟节点:具有相同父节点的节点互称为兄弟节点 - 如上图:B、C是兄弟节点
  • 树的度:一棵树中,最大的节点的度称为树的度 - 如上图:树的度为6
  • 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  • 树的高度/深度:树中节点的最大层次 - 如上图:树的高度为4
  • 堂兄弟节点:双亲在同一层的节点互为堂兄弟 - 如上图:H、I互为兄弟节点
  • 节点的祖先从根到该节点所经分支上的所有节点 - 如上图:A是所有节点的祖先
  • 子孙:以某节点为根的子树中任一节点都称为该节点的子孙 - 如上图:所有节点都是A的子孙
  • 森林:由m(m>0)棵互不相交的树的集合称为森林;
    请添加图片描述

3.树的表示

  • 既然保存值域,也要保存结点和结点之间的关系 - 左孩子右兄弟法

    // 左孩子右兄弟
    typedef int DataType;
    struct BinaryTreeNode
    {
        struct TreeNode* firstChild; // 指向第一个孩子节点
        struct TreeNode *pNextBrother; // 指向其下一个兄弟节点
        DataType data; // 节点中的数据域
    };
    

    请添加图片描述


4.二叉树概念

  • 一棵二叉树是结点的一个有限集合,该集合:

    • 或者为空
    • 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
      请添加图片描述
  • 二叉树不存在度大于2的结点

  • 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树


5.特殊的二叉树

  • 满二叉树

    • 每一个层的结点数都达到最大值,则是满二叉树。
    • 若一个二叉树的层数为K,且结点总数是 2 k − 1 2^k-1 2k1,则它就是满二叉树
  • 完全二叉树

    • 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的
    • 对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树
    • 满二叉树是一种特殊的完全二叉树
    • sum = 2^k - 1
      请添加图片描述

5.二叉树的性质

  • 若规定根节点的层数为1,则一颗非空二叉树的第i层上最多有 2 ( i − 1 ) 2^{(i-1)} 2(i1)
  • 若规定根节点的层数为1,则**深度为h的二叉树的最大结点数量就是 2 k − 1 2^k-1 2k1 **
  • 对任何一颗二叉树,如果度为0其叶节点个数为 n 0 n_0 n0,度为2的分支结点个数为 n 2 n_2 n2,则有 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1
  • 若规定根节点的层数为1,具有n个节点的满二叉树的深度 h = log ⁡ 2 ( n + 1 ) h=\log_2(n+1) h=log2(n+1)
  • 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的节点有:
    • i > 0 i>0 i>0,i位置节点的双亲序号: ( i − 1 ) / 2 (i-1)/2 (i1)/2 i = 0 i=0 i=0,i为根节点编号,无双亲结点
    • 2 i + 1 < n 2i+1<n 2i+1<n,左孩子序号: 2 i + 1 2i+1 2i+1 2 i + 1 > = n 2i+1>=n 2i+1>=n否则无左孩子
    • 2 i + 2 < n 2i+2<n 2i+2<n,右孩子序号: 2 i + 2 2i+2 2i+2 2 i + 2 > = n 2i+2>=n 2i+2>=n否则无右孩子
  • 即下标间父子间的关系
    leftchild = 2 * parent + 1;
    rightchild = 2* parent + 2;
    parent = (child - 1) / 2;
    
  • 完全二叉树中,若节点总数个数为奇数,则没有度为1的节点,如果节点总个数为偶数,只有一个度为1的节点

6.二叉树的存储结构

1.顺序结构

  • 顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费

  • 实际使用中只有才会使用数组来存储

  • 二叉树顺序存储在物理上是一个数组;在逻辑上是一颗二叉树

    请添加图片描述

2.链式结构

  • 用链来指示元素的逻辑关系。

  • 通常的方法是链表中每个结点由三个域组成,数据域左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。

  • 链式结构又分为二叉链三叉链
    请添加图片描述

  • 普通二叉树增删查改没有什么意义

  • 学习其遍历或者控制结构


7.链式结构二叉树

1.二叉树的遍历 – 深度优先遍历(DFS)

  • 由于被访问的结点必是某子树的根
  • 所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树、根的右子树。
  • 前序遍历(Preorder Traversal) ——访问根结点的操作发生在遍历其左右子树之前
    • 根 左子树 右子树
  • 中序遍历(Inorder Traversal) ——访问根结点的操作发生在遍历其左右子树之中(间)
    • 左子树 根 右子树
  • 后序遍历(Postorder Traversal) ——访问根结点的操作发生在遍历其左右子树之后
    • 左子树 右子树 根
      typedef int BTDataType;
      typedef struct BinaryTreeNode
      {
      	struct BinaryTreeNode* left;
      	struct BinaryTreeNode* right;
      	BTDataType data;
      }BTNode;
      
      //深度优先遍历  -  递归思想
      void PreOrder(BTNode* root)
      {
      	assert(root);
      	if (root == NULL)
      	{
      		printf("# ");
      		return;
      	}
       
      	printf("%d ", root->data);
      	PreOrder(root->left);
      	PreOrder(root->right);
      }
       
      void InOrder(BTNode* root)
      {
      	assert(root);
      	if (root == NULL)
      	{
      		printf("# ");
      		return;
      	}
       
      	PreOrder(root->left);
      	printf("%d ", root->data);
      	PreOrder(root->right);
      }
       
      void PostOrder(BTNode* root)
      {
      	assert(root);
      	if (root == NULL)
      	{
      		printf("# ");
      		return;
      	}
       
      	PostOrder(root->left);
      	PostOrder(root->right);
      	printf("%d ", root->data);
      }
      
  • 前序遍历递归图解
    请添加图片描述

2.二叉树的遍历 – 广度优先遍历(DBS)

  • 层序遍历:自上而下,自左至右逐层访问树的结点的过程
    /层序遍历
    //广度优先遍历  -  队列思想
    void LevelOrder(BTNode* root)
    {
    	Queue q;
    	QueueInit(&q);
     
    	//入树根节点
    	if (root)
    	{
    		QueuePush(&q, root);
    	}
     
    	while (!isQueueEmpty(&q));
    	{
    		BTNode* front = QueueFront(&q);
    		QueuePop(&q);
    		printf("%d ", front->data);
     
    		if (root->left)
    		{
    			QueuePush(&q, root->left);
    		}
    		if (root->right)
    		{
    			QueuePush(&q, root->right);
    		}
    	}
    	printf("\n");
     
    	QueueDestroy(&q);
    }
    

3.接口实现

//计数器的形式
int count = 0;
void TreeSize1(BTNode* root)
{
	assert(root);
	if (root == NULL)
	{
		return;
	}
 
	count++;
	TreeSize1(root->left);
	TreeSize1(root->right);
}
 
int TreeSize2(BTNode* root)
{
	assert(root);
	return root == NULL ? 0 : TreeSize2(root->left) + TreeSize2(root->right) + 1;
}
 
int TreeLeafSize(BTNode* root)
{
	assert(root);
	if (root == NULL)
	{
		return 0;
	}
 
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
 
//求K层节点数量 - 前序
int TreeKLevel(BTNode* root, int k)
{
	//转换成子问题
	//求左子树的第k-1层 + 求右子树的第k-1层
	assert(root);
	assert(k >= 1);
 
	if (root == NULL)
	{
		return 0;
	}
 
	if (k == 1)
	{
		return 1;
	}
 
	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}
 
//求二叉树深度 - 后序
int TreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
 
	int leftDepth = TreeDepth(root->left);
	int rightDepth = TreeDepth(root->right);
 
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
 
//查找值为x的节点 - 前序
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
 
	if (root->data == x)
	{
		return root;
	}
 
	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
	{
		return ret1;
	}
 
	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
	{
		return ret2;
	}
 
	return NULL;
}
 
//判断二叉树是否是完全二叉树 - 层序
bool isTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
 
	if (root)
	{
		QueuePush(&q, root);
	}
 
	while (!isQueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
 
		//依次压入所有节点
		if (front)
		{
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
		else
		{
			//遇到NULL节点,跳出层序遍历
			break;
		}
	}
 
	//1.如果后面全是空,则为完全二叉树
	//2.如果后面还有非空,则不是完全二叉树
	while (!isQueueEmpty)
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
 
		if (front)
		{
			return false;
		}
	}
 
	//队列已空,说明后面全是空
	return true;
}
 
//销毁二叉树 - 后序
void TreeDestroy(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
 
	TreeDestroy(root->left);
	TreeDestroy(root->right);
	free(root);
}

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

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

相关文章

计算机组成原理-常见计算题含IEE754

一、补码加减运算 二、溢出判断 采用一位符号位 采用双符号位 三、定点数的移位运算 算术右移 算数左移 反码的算术移位 补码的算术移位 四、浮点数的表示 一个右规的例子 五、IEEE754 移码

微服务之网关

1、什么是微服务网关&#xff1f; 微服务网关是一种用于管理和调度微服务的工具或服务&#xff0c;它在微服务架构中扮演着关键角色。以下是关于微服务网关的清晰概述&#xff1a; 概念定义&#xff1a; 微服务网关是微服务架构中的前端门户&#xff0c;它提供了一个统一的入…

Visual Studio 使用第三方库管理工具 vcpkg

一、介绍 Windows下开发C/C程序&#xff0c;少不了用开源的第三方库。比如线性代数和矩阵分析的库eigen&#xff0c;或者图像处理的OpenCV库。虽然这些库都是开源的&#xff0c;但是由于要编译debug和release版本的&#xff0c;32位以及64位的&#xff0c;如果像FFmpeg…

《云原生安全攻防》-- 容器环境下的攻击行为

在本节课程中&#xff0c;我们将以攻击者的视角来深入探讨容器环境下的攻击行为&#xff0c;并揭示攻击者在容器环境中的各种攻击细节。 在这个课程中&#xff0c;我们将学习以下内容&#xff1a; 攻击容器环境&#xff1a;模拟容器内应用入侵的场景。 容器环境下的攻击行为&a…

876. 链表的中间结点-链表

876. 链表的中间结点 - 力扣&#xff08;LeetCode&#xff09; 快慢指针 class Solution { public:ListNode* middleNode(ListNode* head) {ListNode* slow head;ListNode* fast head;while(fast ! nullptr && fast->next ! nullptr){slow slow->next;fast …

【深度学习驱动流体力学】Python流体力学Ansys Fluent

1、PyFluent&#xff1a;Python Ansys Fluent 的结合 PyFluent 是一个将 Python 编程语言与 Ansys Fluent 流体动力学 (CFD) 仿真软件集成的工具。它允许用户通过 Python 脚本来控制和自动化 Fluent 中的仿真任务&#xff0c;实现从预处理、求解到后处理的全流程控制。PyFlue…

代码随想录 day31|day32

分发饼干 题意&#xff1a; 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都有一个尺寸 s[j] 。如果 s[j] > g[i]&#xff0c;我们可以将这个饼干 j 分配给孩子 i &#xff0c;这…

OJ刷题——2086.AI=?、2087.剪花布条、KPM算法

2086.AI&#xff1f; 题目描述 Problem - 2086 运行代码 #include <iostream> #include <cstdio> using namespace std; const int N 3005; int main() {int n;double Ao, An;double num[N];while (cin>>n) {cin >> Ao>>An;for (int i 1; i…

cve_2014_3120-Elasticsearch-rce-vulfocus靶场

1.背景 来源&#xff1a;ElasticSearch&#xff08;CVE-2014-3120&#xff09;命令执行漏洞复现_mvel 漏洞-CSDN博客 参考&#xff1a;https://www.cnblogs.com/huangxiaosan/p/14398307.html 老版本ElasticSearch支持传入动态脚本&#xff08;MVEL&#xff09;来执行一些复…

STM32智能家居项目esp8266上云OneNet【附源码+详细教程】

目录 一、硬件选材 二、OneNet使用教程 三、代码修改教程 四、添加数据流方法 五、项目工程&#xff08;源码元件清单教程&#xff09; 小白也能做&#xff0c;项目工程在后文可下载。 一、硬件选材 二、OneNet使用教程 拿到代码后肯定是连不上网的&#xff0c;因为源码…

pytest配置文件配置并通过allure生成报告

之前已经学习了使用pytestrequests实现各种方式的调用和一些脚本的执行&#xff0c;今天来学习下如何使用pytest.ini配置文件来管理用例的执行以及如何使用allure生成测试报告。 1.pytest.ini文件配置 在项目目录下新建pytest.ini文件&#xff0c;然后进行配置&#xff0c;pyt…

linux:centos7升级libstdc++版本到3.4.26

下载&#xff0c;解压 wget http://www.vuln.cn/wp-content/uploads/2019/08/libstdc.so_.6.0.26.zip unzip libstdc.so_.6.0.26.zip 复制到【/usr/lib64】&#xff1a; cp libstdc.so.6.0.26 /usr/lib64创建软链接 cd /usr/lib64 sln libstdc.so.6.0.26 libstdc.so.6查看一…

使用 Scapy 库编写 TCP ACK 洪水攻击脚本

一、介绍 TCP ACK洪水攻击是一种分布式拒绝服务攻击&#xff08;DDoS&#xff09;&#xff0c;攻击者通过向目标服务器发送大量伪造的TCP ACK&#xff08;确认&#xff09;数据包&#xff0c;使目标服务器不堪重负&#xff0c;无法正常处理合法请求。虽然ACK包通常用于确认接收…

问题:材料题请点击右侧查看材料问题 查看材料 #学习方法#经验分享#学习方法

问题&#xff1a;材料题请点击右侧查看材料问题 查看材料 A.Colleges may reduce their enrollment. B.Top universities become increasingly competitive. C.Universities become selective in student admission. D.Colleges invest less in academy and infrastructure…

【LLM】Dify 0.6.10 在Windows系统上本地化部署

【LLM】Dify 0.6.10 在Windows系统上本地化部署 文章目录 【LLM】Dify 0.6.10 在Windows系统上本地化部署一、参考资料二、Dify 概述1、Dify开源项目功能介绍&#xff08;RAG流水线&#xff0c;Agent工具接入&#xff0c;Prompt配置和工作流编排&#xff0c;大模型接入&#xf…

浅析嵌入式实时系统中信号量的概念

目录 概述 1. 认识信号量 1.1 定义信号量 1.2 信号量的类型 1.2.1 二值信号量 1.2.2 计数信号量 1.2.3 互斥信号量 1.2.3.1 认识互斥信号量 1.2.3.2 互斥信号量的其他特性 2 典型信号量的使用 2.1 等待和信号同步 2.2 多任务等待和信号同步 2.3 信用跟踪同步 2.…

stm32MP135裸机编程:使用USB/UART烧录程序到SD卡并从SD卡启动点亮一颗LED灯

0 参考资料 轻松使用STM32MP13x - 如MCU般在cortex A核上裸跑应用程序.pdf STM32CubeProgrammer v2.16.0 烧录需要的二进制文件1 烧录到SD卡需要哪些文件 参考《轻松使用STM32MP13x - 如MCU般在cortex A核上裸跑应用程序》&#xff0c;烧录需要的SD卡文件如下&#xff1a; &a…

多模态大模型思路

最近看了一篇苏神的文章&#xff0c;对多模态LLM的设计思考很有启发&#xff0c;总结如下&#xff0c;原文可参考“闭门造车”之多模态模型方案浅谈 - 科学空间|Scientific Spaces 多模态模型要解决什么问题 视频生成、文生图这些内容&#xff0c;图文混合的双模态输入输出&a…

CTF-PWN-kernel-UAF

文章目录 参考slub 分配器kmem_cache_cpukmem_cache_node[ ]冻结和解冻分配释放 fork绑核Kmalloc flag和slub隔离CISCN - 2017 - babydriver检查babtdriver_initstruct cdevalloc_chrdev_regioncdev_initownercdev_add_class_createdevice_create babyopenbabyreleasebabyreadb…

机器视觉系统-同轴光源大小选择技巧

同轴光源多用于检测光滑平面产品上的缺陷&#xff0c;同样利用上述的方法计算得出光源尺寸。 实际上&#xff0c;同轴光源可理解为没有孔的开孔面光&#xff0c;因此可等效为发光面相等的面光源&#xff0c;如下图&#xff1a; 如图所示&#xff0c;同轴光源的效果与开孔面光的…