树和二叉树的基本知识

一、树的概念及结构

1.树的概念

树是一种 非线性 的数据结构,它是由 n n>=0 )个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的
有一个 特殊的结点,称为根结点 ,根节点没有前驱结点。
除根节点外, 其余结点被分成 M(M>0) 个互不相交的集合 T1 T2 …… Tm ,其中每一个集合 Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有 0 个或多个后继。
因此, 树是递归定义 的。
注意:树形结构中,子树之间不能有交集,否则就不是树形结构

2.相关概念

节点的度:一个节点含有的子树个数称为该节点的度。如上图:根节点A的度为5

叶节点/终端节点:度为0的节点称为叶节点。如上图:B、D、G、I、K、L、M、N、O均为叶节点

分支节点/非终端节点:度不为0的节点。如上图:C、E、F、H、J为分支节点

双亲节点或父节点 :若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图: A B 的父节点
孩子节点或子节点 :一个节点含有的子树的根节点称为该节点的子节点; 如上图: B A 的孩子节点
兄弟节点 :具有相同父节点的节点互称为兄弟节点; 如上图: B C 是兄弟节点
树的度 :一棵树中,最大的节点的度称为树的度; 如上图:树的度为5
节点的层次 :从根开始定义起,根为第 1 层,根的子节点为第 2 层,以此类推
树的高度或深度 :树中节点的最大层次; 如上图:树的高度为 4
节点的祖先 :从根到该节点所经分支上的所有节点;如上图: A 是所有节点的祖先
子孙 :以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是 A 的子孙
森林 m m>0 )棵互不相交的树的集合称为森林

3.树的表示

实际中树的表示方法有很多种,最常用的是链式存储结构的孩子兄弟表示法:

typedef int DataType;
struct Node
{struct Node* _firstChild; // 指向其第一个孩子结点struct Node* _Brother; // 指向其兄弟结点DataType _data; // 结点中的数据域
};

例如,上图的部分节点表示如下:

4.树的性质

①设度为i的节点个数为n_{i},则对于一颗度为m的树,其总节点个数N = n_{0}+n_{1}+...+n_{m}

②所有节点的度之和n_{1}+2n_{2}+...+mn_{m}=N-1

二、二叉树的概念

1.概念

一棵二叉树是结点的一个有限集合,该集合 :
1. 或者为空
2. 或者 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
从定义可以看出,二叉树的度小于等于2,即不存在度大于2的节点。因此,任意一颗二叉树都是由以下几种情况复合而成的:
注意:二叉树≠度为2的树:二叉树的度可以为0/1/2,但度为2的树的度必须为2,即度为2的树必须存在度为2的节点,而二叉树没有此限制。

2.特殊的二叉树

满二叉树 :一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
也就是说,如果一个二叉树的层数为K ,且结点总数是2^{k}-1,则它就是满二叉树。
完全二叉树 :完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为 K的,有n 个结点的二叉树,当且仅当其每一个结点都与深度为 K 的满二叉树中编号从 1 n 的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树

3.二叉树的性质

①若规定根节点的层数为 1 ,则一棵非空二叉树的 i 层上最多有 2^{i-1}个结点
若规定根节点的层数为 1 ,则 深度为 h 的二叉树的最大结点数是2^{h}-1
③由树的性质可知,N=n_{0}+n_{1}+n_{2}n_{1}+2n_{2}=N-1,联立上式可得n_{0}=n_{2}+1
④若规定根节点的层数为 1 ,具有 n 个结点的满二叉树的深度 h=log_{2}(n+1)

三、二叉树的存储结构

1.顺序存储

顺序存储就是使用一个数组来存储,顺序存储一般只适用于完全二叉树或近似于完全二叉树,否则会造成较大的空间浪费。现实使用中只有堆才会使用数组存储,关于堆的内容将在下篇博客【堆的实现及应用】讲解。

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

2.链式存储

二叉树的链式存储结构是指,用链表来表示一颗二叉树,即用链来指示元素的逻辑关系。通常链表中的每个节点由三个域组成:数据域、左指针域、右指针域。其中左右指针域分别给出该节点左孩子和右孩子所在链节点的地址。这种链式结构又叫做二叉链。

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType val;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;

一颗二叉树可以分为三部分:根节点、左子树、右子树,而左右子树又都是一颗二叉树,可见二叉树的结构具有递归性,因此基于链式存储结构的二叉树算法多数也是递归的,这样代码的可读性更高、容易理解。

(1)二叉树的遍历

二叉树遍历是指按照某种特定规则依次访问二叉树的全部节点,每个节点只访问一次。

遍历是二叉树最重要的算法之一,也是其他算法的基础。

二叉树的遍历可分为四种:

①前序遍历:按照根节点、左子树、右子树的顺序遍历二叉树。如上图,遍历结果为1 2 4 6 5 3

②中序遍历:按照左子树、根节点、右子树的顺序遍历二叉树。如上图,遍历结果为4 6 2 5 1 3

③后序遍历:按照左子树、右子树、根节点的顺序遍历二叉树。如上图,遍历结果为6 4 5 2 3 1

④层序遍历:从根节点开始,自上而下、自左至右逐层访问二叉树的每个节点。如上图,遍历结果为1 2 3 4 5 6

其中,前三种遍历方式均属于递归遍历,第四种为非递归遍历。

下面以前序遍历为例演示递归遍历:

void PreOrder(BTNode* t)
{if (t == NULL){printf("NULL ");return;}printf("%d ", t->val);PreOrder(t->left);PreOrder(t->right);
}

层序遍历需要借助队列来实现,使用队列保存每个节点的孩子节点,通过不断地入队和出队以此来实现所有节点的访问:(注:有关队列的接口函数均与上篇博客中保持一致)

void LevelOrder(BTNode* t)
{Queue qu;QueueInit(&qu);QueuePush(&qu, t);while (!QueueEmpty(&qu)){BTNode* tmp = QueueFront(&qu);QueuePop(&qu);printf("%d ", tmp->val);if (tmp->left != NULL)QueuePush(&qu, tmp->left);if (tmp->right != NULL)QueuePush(&qu, tmp->right);}
}

(2)二叉树的创建和销毁

已知一颗二叉树的某种递归遍历序列,如何构建出对应的二叉树?下面以前序序列为例:(注:子树为空用‘#’表示)

//创建单个节点
BTNode* SingleNode(BTDataType x)
{BTNode* _new = (BTNode*)malloc(sizeof(BTNode));if (_new == NULL){perror("malloc error");exit(-1);}_new->val = x;_new->left = NULL;_new->right = NULL;return _new;
}//创建二叉树
BTNode* CreateBT(char* a, int* pi)  //pi为遍历序列a的下标,开始为0
{if (a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("malloc error");exit(-1);}root->val = a[(*pi)++]-'0';  //注意数据类型root->left = CreateBT(a, pi);root->right = CreateBT(a, pi);return root;
}

二叉树的销毁:

void BTDestroy(BTNode** pt)
{BTNode* t = *pt;if (t == NULL)return;BTDestroy(&(t->left));BTDestroy(&(t->right));free(t);*pt = NULL;
}

(3)其他算法

下面列举了一些有关二叉树遍历的其他算法,可以加深对递归遍历和链式结构的理解。当然,这些算法题在各大OJ平台都可以搜到。

①计算二叉树的节点个数:

int TreeNodeSize(BTNode* t)
{if (t == NULL)return 0;return TreeNodeSize(t->left) + TreeNodeSize(t->right) + 1;
}

②计算二叉树叶子节点的个数:

int LeafSize(BTNode* t)
{if (t == NULL)return 0;if (t->left == NULL && t->right == NULL)return 1;return LeafSize(t->left) + LeafSize(t->right);
}

③计算二叉树的高度:

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

④计算第k层的节点个数:

int Size_k(BTNode* t,int k)
{if (t == NULL)return 0;if (k == 1)return 1;return Size_k(t->left, k - 1) + Size_k(t->right, k - 1);
}

⑤查找值为x的节点:

BTNode* BTFind(BTNode* t, BTDataType x)
{if (t == NULL)return NULL;if (t->val == x)return t;BTNode* t1 = BTFind(t->left, x);if (t1 != NULL)return t1;elsereturn BTFind(t->right, x);
}

⑥判断两棵树是否相同:

bool isSameTree(BTNode* p, BTNode* q) 
{if (p == NULL && q == NULL)  //在条件判别时,p==NULL等价于!preturn true;if (p == NULL || q == NULL)return false;if (p->val != q->val)return false;bool left = isSameTree(p->left, q->left);bool right = isSameTree(p->right, q->right);return left && right;
}

⑦翻转二叉树:

BTNode* invertTree(BTNode* root) 
{if (root == NULL)return NULL;BTNode* _root = (BTNode*)malloc(sizeof(BTNode*));if (_root == NULL){perror("malloc error");exit(-1);}_root->val = root->val;_root->left = invertTree(root->right);_root->right = invertTree(root->left);return _root;
}

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

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

相关文章

2024春节过后,抖店爆款出单类目产品,应季产品需要提前布局

我是王路飞。 之前给你们强调过&#xff0c;“应季品”是最容易爆单的产品类型&#xff0c;没有之一。 那么在2024年春节刚过的现在&#xff0c;当别人还沉浸在过年的氛围中时&#xff0c;有心的商家早就开始布局未来三个月的爆款类目和产品了。 今天的内容&#xff0c;就给…

软件实例分享,乒乓球俱乐部会员系统管理软件教程

软件实例分享&#xff0c;乒乓球俱乐部会员系统管理软件教程 一、前言 以下软件程序教程以 佳易王乒乓球馆计时计费软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 多种计费方式&#xff0c;可以按单价&#xff0c;也可以按时间段 可…

2942. 查找包含给定字符的单词【简单】

2942. 查找包含给定字符的单词【简单】 题目描述&#xff1a; 给你一个下标从 0 开始的字符串数组 words 和一个字符 x 。 请你返回一个 下标数组 &#xff0c;表示下标在数组中对应的单词包含字符 x 。 注意&#xff1a;返回的数组可以是 任意 顺序 示例 1&#xff1a; 输…

vue3 Element Plus 基于webstorm练习

提要 vue是前端框架&#xff0c;Elemen是组件库。前端框架和组件库的区别与联系 nodejs 脚本语言需要一个解析器才能运行&#xff0c;JavaScript是脚本语言&#xff0c;在不同的位置有不一样的解析器&#xff0c;如写入html的js语言&#xff0c;浏览器是它的解析器角色。而对…

python in Vscode

背景 对于后端的语言选择&#xff1a; python&#xff0c;java&#xff0c;JavaScript备选。 选择Python 原因&#xff1a;可能是非IT专业的人中&#xff0c;会Python的人比较多。 目的 之前使用的IDE是VSCODE&#xff0c;在WSL的环境下使用。现在需要在在WSL的VSCODE下使…

【Java程序员面试专栏 Java领域】Java Spring框架 核心面试指引

关于Java Spring框架部分的核心知识进行一网打尽,主要包括Spring框架中的重点概念IOC和AOP,以及SpringBoot的自动装配机制,SpringMVC的核心执行流程,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 基础概念 Spring框架的基本概念,S…

浅谈语义分割、图像分类与目标检测中的TP、TN、FP、FN

语义分割 TP&#xff1a;正确地预测出了正类&#xff0c;即原本是正类&#xff0c;识别的也是正类 TN&#xff1a;正确地预测出了负类&#xff0c;即原本是负类&#xff0c;识别的也是负类 FP&#xff1a;错误地预测为了正类&#xff0c;即原本是负类&#xff0c;识别的是正类…

秒懂百科,C++如此简单丨第二十一天:栈和队列

目录 前言 Everyday English 栈&#xff08;Stack&#xff09; 图文解释 实现添加删除元素 实现查看清空栈 完整代码 运行示例 栈的选择题 队列&#xff08;Queue&#xff09; 图文解释 队列的基本用法 完整代码 运行结果 队列的好处 结尾 前言 今天我们将…

java 培训班预定管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 培训班预定管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xf…

智能扭矩系统——SunTorque

随着工业自动化的不断发展&#xff0c;智能扭矩系统作为一种新型的扭矩控制技术&#xff0c;逐渐受到广泛关注。智能扭矩系统是一种基于传感器技术和计算机控制的扭矩管理系统&#xff0c;它能够实时监测和调整设备的扭矩输出&#xff0c;以确保生产过程中的稳定性和安全性。 搭…

采用文件路径安装库到不同的python环境

C:\Users\Administrator>pip3 install --targetD:\PycharmProjects\pythonProject3\venv\Lib\site-packages configparser

Aquarius Fantasy Series Orcs

使用标准管道创建。目前不支持URP或HDRP。 - 如果想将其转换为URP或类似材质。90%的材质可以完美转换。但是树叶材质和岩石顶盖材质无法转换,除非有自己的材质,无论是自己制作的,还是其他资源包。布料也是如此,每块布料都是单面的,使用简单的材质来达到双面效果。所有其他…

IOC理解总结

IOC 控制反转&#xff08;Inversion of Control&#xff0c;缩写为IoC&#xff09;&#xff0c;是面向对象编程中的一种设计原则&#xff0c;可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09…

21种matlab信号分解方法汇总

21中信号分解方法汇总 CEEMD(互补集合经验模态分解)CEEMDAN(自适应噪声完备集合经验模态分解) EEMD(集合经验模态分解&#xff09;EMD(经验模态分解)ESMD(极点对称模态分解&#xff09;EWT(经验小波变换分解)FEEMD(快速EEMD分解)ICEEMDAN(改进自适应噪声完备集合经验模态分解)L…

BuildAdmin - 免费开源可商用!基于 ThinkPHP8 和 Vue3 等流行技术栈打造的商业级后台管理系统

一款包含 PHP 服务端和 Vue 前端代码的 admin 管理系统&#xff0c;实用性很强&#xff0c;推荐给大家。 BuildAdmin 是一个成熟的后台管理系统&#xff0c;后端服务采用 ThinkPHP8 &#xff0c;数据库使用 Mysql&#xff0c;前端部分则使用当前流行的 Vue3 / TypeScript / Vi…

HDFS 命令实操

在hdfs中创建文件夹&#xff1a;/itcast/itheima&#xff0c;如存在请删除&#xff08;跳过回收站&#xff09; 上传Linux文件系统中的/etc/hosts文件到hdfs的/itcast/itheima内 查看hdfs中刚刚上传的文件内容 向hdfs中上传的文件追加&#xff1a;itheima到最后一行 下…

从物联网到数字孪生:智慧社区的演变

随着科技的飞速发展和数字化转型的深入推进&#xff0c;智慧社区已成为提升城市治理水平和居民生活质量的重要方向。在这一演变过程中&#xff0c;物联网和数字孪生技术起到了至关重要的作用。本文将深入探讨从物联网到数字孪生的演变过程&#xff0c;分析这一转变对智慧社区建…

初识数据库:探索数据的世界

初识数据库&#xff1a;探索数据的世界 1. 什么是数据库&#xff1f;2. 数据库的类型2.1 关系型数据库&#xff08;RDBMS&#xff09;2.2 非关系型数据库&#xff08;NoSQL&#xff09; 3. 为什么使用数据库&#xff1f;4. 如何选择合适的数据库&#xff1f;5. 结语 在信息技术…

Python中 ‘==‘ 与‘is‘的区别

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 比较判断逻辑是在代码中经常使用的&#xff0c;在Python中常用 ‘’ 和 is 来做比较判断。 : 双等号是用来比较变量所指向内存单元中的值是否相等&#xff0c;它只关心值&#xff0c;并不在意值的内存地址&#xff0c;也就是说…

Python+appium框架原生代码实现App自动化测试

step1&#xff1a;首先介绍下pythonappium的框架结构&#xff0c;如下截图所示 (1)&#xff1a;apk目录主要放置待测app的apk资源&#xff1b; (2)&#xff1a;config目录主要放置配置文件信息&#xff0c;包含&#xff1a;数据库连接配置、UI自动化脚本中所需的页面元素信息及…