探索数据结构:树与二叉树

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:数据结构与算法
贝蒂的主页:Betty’s blog

1. 树

1.1. 树的定义

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

img

在树中有一个特殊的结点,称为根结点,根节点没有前驱结点

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

img

注意:树形结构中,子树之间不能有交集,否则就不是树形结构

img

1.2. 树的基本概念

术语定义
节点的度一个节点含有的子树的个数称为该节点的度,比如说节点1的度为2
叶节点度为0的节点,比如说4,5,6节点
分支节点度不为0的节点,比如说2,3节点
双亲节点若一个节点含有子节点,则这个节点称为其子节点的父节点。比如说2是4,5的双亲节点
子节点一个节点含有的子树的根节点称为该节点的子节点,比如说4,5是2的子节点
兄弟节点具有相同父节点的节点互称为兄弟节点,比如说4,5就是兄弟节点
树的度一棵树中,最大的节点的度称为树的度,比如说上面这棵树的度为2
节点的层次从根开始定义起,根为第1层,根的子节点为第2层,以此类推
树的高度或深度树中节点的最大层次,比如说上面这棵树的高度为3
堂兄弟节点双亲在同一层的节点互为堂兄弟,比如说5,6节点
节点的祖先从根到该节点所经分支上的所有节点,比如说1就是所有节点的祖先
子孙以某节点为根的子树中任一节点都称为该节点的子孙,比如说所有节点都是1的子孙
森林由m(m>0)棵互不相交的树的集合称为森林

1.3. 树的表示方法

下面我们将采用三种方式表示下面这课树:

img

1.3.1. 双亲表示法

双亲表示法采用顺序表的方式存储,即用顺序表存储各个节点的数据,并且同时存储其双亲节点的下标。注意:根节点没有双亲节点,所以特别记为-1。

#define MAX_SIZE 10
typedef int DataType;
typedef struct Node
{DataType data;//数据域int parent; //双亲结点在数组中的位置下标
}Node;
typedef struct PTree
{//存放树中所有结点Node tnode[MAX_SIZE];//当前结点个数int n;
}PTree;

img

1.3.2. 树的孩子表示法

树的孩子表示法就是采用顺序表与链表结合的形式,用顺序表存储树的值与链表的头节点,而链表的头节点存储其孩子节点在顺序表中的下标,若没有则记为空(N)。

#define MAX_SIZE 10
#define DataType int
typedef struct ListNode 
{int child;struct ListNode* next;
}ListNode;
typedef struct TNode
{DataType data;//孩子链表的头指针ListNode* firstchild;
}TNode;
typedef struct PTree{//存储结点的数组TNode nodes[MAX_SIZE];int n; //结点数量
}PTree;

img

1.3.3. 左孩子右兄弟表示法

最常用表示树的的方法就是左孩子右兄弟表示法,即定义两个指针,让左指针指向子节点,右指针指向兄弟节点。

如果没有节点,则都指向空。

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

img

1.4. 树的实际应用

在linux环境下目录结构就是有一颗树构成,而在Windows环境下,目录许多内容并不交叉,所以是由森林构成。

img

2. 二叉树

2.1. 二叉树的定义

一棵二叉树是结点的一个有限集合,该集合可能为空,也可以由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

注意:

  1. 二叉树不存在度大于2的结点
  2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

img

img

2.2. 特殊的二叉树

2.2.1. 满二叉树

满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是N=2k -1,则它就是满二叉树。

img

2.2.2. 完全二叉树

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

img

2.3. 二叉树的特点

  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2i -1个结点。
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数N=1+2+4+…+2i -1=2h -1
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为N0, 度为2的分支结点个数为N2, 则有 N0=N2+1

证明如下:

假设节点总数为N,如果度为0其叶结点个数为N0, 度为1的分支结点个数为N1,度为2的分支结点个数为N2

节点总数:N=N0 + N1+ N2 又因为二叉树的边比节点树少1,所以N= N1 +2N2+1=>N0 + N1+ N2= N1 +2N2+1=>N0=N2+1

  1. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h =log2 (n+1) 。

  2. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对

​ 于序号为i的结点有:

1. 若i > 0,i位置节点的双亲序号:(i - 1) / 2;i = 0,i为根节点编号,无双亲节点。

2. 若2i + 1 < n,左孩子序号:2i + 1,2i + 1 >= n否则无左孩子。

3. 若2i + 2 < n,右孩子序号:2i + 2,2i + 2 >= n否则无右孩子。

2.4. 二叉树的存储

2.4.1. 数组存储

我们可以通过双亲节点与子节点下标之间的映射关系将二叉树存储在数组中,如果节点为空,我们以INT_MAX来标记。

img

2.4.2. 链式存储

除了数组存储,我们也可以链式存储二叉树。

typedef struct BinaryTreeNode
{struct BinTreeNode* left; // 左孩子struct BinTreeNode* right; // 右孩子DataType data; // 当前节点值域
}BTree;

2.5. 二叉树的遍历

二叉树的遍历一般有四种方法:前序遍历,中序遍历,后序遍历,层序遍历。

img

2.5.1. 前序遍历

前序遍历:先遍历根节点,再依次遍历左子树,右子树。而遍历左子树,又要先遍历根节点,再依次遍历左子树,右子树…直至遍历到空树。

  1. 递归实现
void PreOrder(BTree*root)
{if (root == NULL){return;}printf("%d ", root->data);//根节点PreOrder(root->left);//左子树PreOrder(root->right);//右子树
}
  1. 非递归实现

非递归实现树的前序遍历我们需要借助栈这个数据结构,来达到与递归一样的深度优先遍历的目的。并且栈中存储元素为BTree*

  typedef BTree* STDataType;void PreOrder(BTree* root){Stack s;				InitStack(&s);			  BTree*p = root;// p为遍历指针while (p || !IsEmpty(&s))  // 栈不为空或p不为空时循环{if(p!=NULL)//入栈{printf("%d ", p->data);//根节点StackPush(&s, p);p = p->left;}else//出栈,访问右子树{p = StackTop(&s);//访问原本双亲节点StackPop(&s);	  // 栈顶元素出栈p = p->right; //访问}					 }}
2.5.2. 中序遍历

中序遍历:先遍历左子树,再依次遍历根节点,右子树。而遍历左子树,又要先遍历左子树,再依次遍历根节点,右子树…直至遍历到空树。

  1. 递归实现
void Inorder(BTree*root)
{if (root == NULL){return;}PreOrder(root->left);//左子树printf("%d ", root->data);//根节点PreOrder(root->right);//右子树
}
  1. 非递归实现

非递归实现树的中序遍历我们需要借助栈这个数据结构,来达到与递归一样的深度优先遍历的目的。并且栈中存储元素为BTree*

  typedef BTree* STDataType;void Inorder(BTree* root){Stack s;InitStack(&s);BTree* p = root;// p为遍历指针while (p || !IsEmpty(&s))  // 栈不为空或p不为空时循环{if (p != NULL)//入栈{StackPush(&s, p);p = p->left;}else//出栈,访问右子树{p = StackTop(&s);//访问原本双亲节点StackPop(&s);	  // 栈顶元素出栈printf("%d ", p->data);p = p->right; //访问}}}
2.5.3. 后序遍历

后序遍历:先遍历左子树,再依次遍历右子树,根节点。而遍历左子树,又要先遍历左子树,再依次遍历右子树,根节点…直至遍历到空树。

  1. 递归实现
void Postorder(BTree*root)
{if (root == NULL){return;}PreOrder(root->left);//左子树PreOrder(root->right);//右子树printf("%d ", root->data);//根节点
}
  1. 非递归实现

非递归实现树的后序遍历我们需要借助栈这个数据结构,来达到与递归一样的深度优先遍历的目的。并且栈中存储元素为BTree*

void Postorder(BTree* root)
{Stack s;InitStack(&s);BTree* p = root;// p为遍历指针BTree* v = root;// v标记已访问节点while (p || !IsEmpty(&s))  // 栈不为空或p不为空时循环{while(p != NULL)//入栈{StackPush(&s, p);p = p->left;}p = StackTop(&s);//访问双亲节点if (p->right && p->right != v)//存在右子树,且没有被访问{p = p->right;//访问}else//没有右子树或者右子树已被访问{printf("%d ", p->data);v = p;//记录当前访问的节点p = NULL;//防止重复访问左子树StackPop(&s);// 栈顶元素出栈}}
}
2.5.4. 层序遍历

img

层序遍历顾名思义就是一层一层地遍历,这时就需要借助一个数据结构:队列来辅助实现。

void leverOrder(BTree* root, Queue* pq)
{if (root == NULL)//为空直接返回{return;}QueuePush(pq, root);//插入第一个节点while (!QueueEmpty(pq))//队列不为空{BTree* p = QueueFront(pq);printf("%d ", p->val);QueuePop(pq);if (p->left != NULL)//带入左孩子{QueuePush(pq, p->left);}if (p->right != NULL)//带入右孩子{QueuePush(pq, p->right);}}
}

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

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

相关文章

ORA-609频繁出现在alert.log,如何解决?

ORA-609就alertlog中比较常见的一个报错&#xff0c;虽然并没有太大的影响&#xff0c;但是频繁的出现在alert log也是很让人厌烦的事情&#xff0c;本文介绍如何排查解决ORA-609问题。 1.ORA-609官方定义 could not attach to incoming connection Cause Oracle process cou…

【SRC实战】前端脱敏信息泄露

挖个洞先 https://mp.weixin.qq.com/s/xnCQQCAneT21vYH8Q3OCpw “ 以下漏洞均为实验靶场&#xff0c;如有雷同&#xff0c;纯属巧合 ” 01 — 漏洞证明 一、前端脱敏&#xff0c;请求包泄露明文 “ 前端脱敏处理&#xff0c;请求包是否存在泄露&#xff1f; ” 1、获取验…

|Python新手小白中级教程|第二十八章:面向对象编程(类定义语法私有属性类的继承与多态)(4)

文章目录 前言一、类定义语法二、私有方法和私有属性1.私有属性2.私有方法 三、类“继承”1.初识继承2.使用super函数调用父类中构造的东西 四、类“多态”1.多态基础2.子类不同形态3.使用isinstance函数与多态结合判断类型 总结 前言 大家好&#xff0c;我是BoBo仔吖&#xf…

6818Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…

Task Office for Mac v9.0激活版:任务管理新境界

还在为繁琐的任务管理而烦恼吗&#xff1f;Task Office for Mac为您带来全新的任务管理体验。简洁明了的界面设计&#xff0c;让您轻松上手&#xff1b;强大的任务管理和项目管理功能&#xff0c;让您轻松掌握任务进度&#xff1b;多用户协作功能&#xff0c;让团队协作更加高效…

Excel办公技巧之下拉菜单

在日常办工中&#xff0c;经常需在单元格中输入特定的值&#xff0c;此时我们可以使用下拉菜单解决&#xff0c;输入错误和错误值&#xff0c;可以一劳永逸的解决固定数据输入问题。 使用Excel下拉菜单时&#xff0c;它在数据输入和验证方面发挥着重要作用通过点击单元格的下拉…

商业数据分析--时间序列图及趋势分析

绘制时间序列图,并指出存在什么样的状态如上两图: 可见状态:从时间序列图可以看出,这些数据存在明显的季节性波动,每年的第4季度值都最高,而第2季度值最低。同时也存在一些下降的趋势。 通过引进虚拟变量,建立多元线性回归模型。答: 通过引入虚拟变量,我们可以建立如下的…

商场学习之微服务

前言 寒假前在新电脑上配置了java环境&#xff0c;maven仓库&#xff0c;node,js&#xff0c;navicat&#xff0c;MySQL&#xff0c;linux&#xff0c;vmware等环境&#xff0c;创建了6个mysql数据库&#xff0c;77张表。 如此多的表&#xff0c;字段&#xff0c;去手写基础…

Web入门——三栏布局页面

前置知识 内外边距 内边距(padding)&#xff1a; padding是元素边框与其内容之间的空间。也就是说&#xff0c;如果你给一个元素设置了内边距&#xff0c;这个空间会作为元素内容与元素边框之间的缓冲区域。设置内边距会使元素本身变大。例如padding:10px就创建了10像素的空间…

Qt之QMqtt 发送图片数据

简述 MQTT(消息队列遥测传输)是ISO标准下基于发布/订阅范式的消息协议;它工作在TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议,为此,它需要一个消息中间件; MQTT是一个基于客户端-服务器的消息发布/订阅传输协议;MQT…

Docker in Docker(DinD)原理与实战

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker幻想曲&#xff1a;从零开始&#xff0c;征服容器宇宙》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Docker简介 2、Docker …

使用 AI Assistant for Observability 和组织的运行手册增强 SRE 故障排除

作者&#xff1a;Almudena Sanz Oliv, Katrin Freihofner, Tom Grabowski 通过本指南&#xff0c;你的 SRE 团队可以实现增强的警报修复和事件管理。 可观测性 AI 助手可帮助用户使用自然语言界面探索和分析可观测性数据&#xff0c;利用自动函数调用来请求、分析和可视化数据…

windows系统安装Ubuntu子系统

安装前先在 控制面板 中打开 程序与功能选项 &#xff0c;点击 启用或关闭Windows功能&#xff1a; 勾选 适用于 Linux的Windows子系统 和 虚拟机平台 、 Hyper-v 。 重启电脑后再 Microsoft Store Windows应用商店 中下载合适的Ubuntu版本。 运行Ubuntu程序&#xff0c;如出现…

【实战】算法思路总结

面试过程中&#xff0c;总是被拷打&#xff0c;信心都要没了。但是也慢慢摸索出一些思路&#xff0c;希望对大家有帮助。 &#xff08;需要多用一下ACM模式&#xff0c;力扣模式提供好了模板&#xff0c;自己在IDEA里面写的话&#xff0c;还是会有些陌生&#xff09; 0、基本…

Unity Editor 找物体助手

找啊找朋友~ &#x1f371;功能介绍&#x1f959;使用方法 &#x1f371;功能介绍 &#x1f4a1;输入相关字符串&#xff0c;它会帮你找到名称中带有该字符串的所有物体&#xff0c;还会找包含该字符串的Text、TextMeshProUGUI。 &#x1f959;使用方法 &#x1f4a1;导入插…

小学拼音弄一下

import re from xpinyin import Pinyindef remove_middle_characters(text):# 仅保留汉字chinese_chars re.findall(r[\u4e00-\u9fff], text)cleaned_text .join(chinese_chars)# 如果字符数为偶数&#xff0c;则在中间添加空格if len(cleaned_text) % 2 0:middle_index le…

【北京迅为】《iTOP-3588从零搭建ubuntu环境手册》-第5章 安装SSH

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

从0开始学python(七)

目录 前言 1 break、continue和pass函数 1.1 break 1.2 continue 1.3 pass 2、序列的索引及切片操作 2.1字符串的索引和切片 2.1.1 字符串索引 2.1.2 字符串切片 总结 前言 上一篇文章我们介绍了python中的循环结构&#xff0c;包括for和while的使用。本章接着往下讲。…

腾讯云服务器之ssh远程连接登录及转发映射端口实现内网穿透(实现服务器访问本地电脑端口)

目录 一、创建密钥绑定实例二、设置私钥权限三、ssh远程连接到服务器四、修改root密码五、端口转发&#xff08;实现服务器访问本地电脑的端口&#xff09; 一、创建密钥绑定实例 创建密钥会自动下载一个私钥&#xff0c;把这个私钥复制到c盘 二、设置私钥权限 1、删除所有用户…

免费剪辑的素材资源网站,超高清、可商用、不限速、无版权,迅速有效的解决您的视频剪辑难题!

在数字媒体时代&#xff0c;高质量的剪辑素材已成为视频制作的核心资源。下面为您推荐的优质视频剪辑素材网站&#xff0c;都提供超高清、无限速、无版权、可商用的素材&#xff0c;这些网站将大大提升您的视频制作效率和质量 01. 蛙学府 实用性&#xff1a;★★★★☆ 丰富性&…