数据结构 --树和森林

news2025/4/22 9:10:33

树和森林

树的存储结构

树的逻辑结构

树是一种递归定义的数据结构

树是n(n≥0)个结点的有限集。当n=0时,称为空树。在任意一棵非空树中应满足:

1)有且仅有一个特定的称为根的结点。

2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2…,Tm,其中每个集合本身又是一棵树,并且称为根的子树。

二叉树:每个分支节点最多只有两棵子树

树:一个分支节点可以有多颗子树

对于一颗普通的树只依靠数组下标,无法反映节点之间的逻辑关系

双亲表示法(顺序存储)

基于树的特点:除了根结点,每个结点有且只有一个双亲(父节点)

//树的存储 -- 双亲表示法
#define MAX_TREE_SIZE 100			//树中最多结点数
typedef struct{						//树的结点定义
    ElemType data;					//数据元素
    int parent;						//双亲位置域
}PTNode;
typedef struct{						//树的类型表示
    PTNode nodes[MAX_TREE_SIZE];	//双亲表示
    int n;			//结点数
}

【拓展】双亲表示法也可以用于存储“森林”

【优缺点】

优点:找双亲(父节点)很方便

缺点:找孩子不方便,只能从头到尾遍历整个数组

适用于找“父亲多”,找“孩子”少的场景。如:并查集

孩子表示法(顺序存储+链式存储)

用数组顺序存储各个节点。每个节点中保存数据元素、孩子链表头指针(顺序存储+链式存储结合)

//树的存储 -- 孩子表示法
struct CNode{
    int child;	//孩子结点在数组中的位置
    struct CNode *next;		//下一个孩子
}
typedef struct{
    ElemType data;
    struct CNode *firstChild;	//第一个孩子
}CTBox;
typedef struct{
    CTBox nodes[MAX_TREE_SIZE];
    int n,r;		//结点数和根的位置
}CTree;

【拓展】孩子表示法也可以用于存储“森林”

如果使用孩子表示法存储森林,需要记录多个根的位置

【优缺点】

优点:找孩子很方便

缺点:找双亲(父节点)不方便,只能遍历每个链表

适用于找“孩子”多,找“父亲”少的场景。如:服务流程树

孩子兄弟表示法(链式存储)
//树的存储 -- 孩子兄弟表示法(左孩子右兄弟)
typedef struct CSNode{
    ElemType data;							//数据域
    struct CSNode *firstchild,*nextsibling;	//第一个孩子和右兄弟指针
}CSNode,*CSTree;

从存储视角来看形态上与二叉树类似

【拓展】双亲表示法也可以用于存储“森林”

用于存储森林时,将森林中的每一棵树的根结点视为平级的兄弟关系

树、森林与二叉树之间的转换

树→二叉树的转换(孩子兄弟表示法)

技巧:

①现在二叉树中,画一个根结点

②按“树的层序”依次处理每个节点

处理一个结点的方法是:如果当前处理的结点中在树中右孩子,就把所有孩子节点“用右指针串在一起”,并在二叉树中把第一个孩子挂在当前结点的左指针下方

在这里插入图片描述

森林→二叉树的转化(孩子兄弟表示法)

技巧:

①先把所有树的根结点画出来,在二叉树中用右指针串起来

②按“森林的层序”依次处理每个节点

处理一个结点的方法是:如果当前处理的结点中在树中右孩子,就把所有孩子节点“用右指针串在一起”,并在二叉树中把第一个孩子挂在当前结点的左指针下方

在这里插入图片描述

二叉树→树的转换

技巧:

①先画出树的根结点

②从树的根结点开始,按“树的层序”恢复每个结点的孩子

恢复一个结点的孩子:在二叉树中,如果当前处理的结点有左孩子,就把左孩子和“用右指针与根结点相连的一整串”拆下来,按顺序挂在当前节点的下方

在这里插入图片描述

二叉树→森林的转换

技巧:

①先把二叉树的根结点和“用右指针与根结点相连的一整串”拆下来,作为多棵树的根结点

②按“森林的层序”恢复每个结点的孩子

恢复一个结点的孩子:在二叉树中,如果当前处理的结点有左孩子,就把左孩子和“用右指针与根节点相连的一整串”拆下来,按顺序挂在当前节点的下方

在这里插入图片描述

树、森林的遍历

树的遍历

先根遍历(深度优先遍历)

若树非空,先访问根结点,再依次对每颗子树进行先根遍历。

树的先根遍历序列与这棵树相对应的二叉树的先序序列相同

//树的先根遍历(伪代码)
void PreOrder(TreeNode *R){
    if(R!=NULL){
        visit(R);	//访问根节点
        while(R还有下一个子树T)
            PreOrder(T);
    }
}

后根遍历(深度优先遍历)

若树非空,先依次对每颗子树进行后根遍历,再访问根结点。

树的后根遍历序列与这棵树相对应的二叉树的中序序列相同

void PostOrder(TreeNode *R){
    if(R != NULL){
        while(R还有下一个子树T)
            PostOrder(T);	//后根遍历下一棵子树
        visit(R);		//访问根结点
    }
}

层序遍历(广度优先遍历)

(需要利用队列实现)

① 若树非空,则根节点入队

② 若队列非空,队头元素出队并访问,同时将该元素的孩子依次入队

③ 重复②直到队列为空

森林的遍历

先序遍历

若森林非空,则按以下规则进行遍历:

① 访问森林中第一棵子树的根结点

② 先序遍历第一棵树中根结点的子树森林

③ 先序遍历除去第一颗树之后剩余的树构成的森林

效果等同于依次对各个树进行先根遍历

效果等同于对与这片森林对应的二叉树进行先序遍历

中序遍历

若森林非空,则按以下规则进行遍历:

① 中序遍历森林中第一棵树的根节点的子树森林

② 访问第一棵树的根结点

③ 中序遍历除去第一颗树之后剩余的树构成的森林

效果等同于依次对各个树进行后根遍历

效果等同于对与这片森林对应的二叉树进行中序遍历

[!TIP]

如果考试考到森林的相关代码题目,可以把森林转化成二叉树,然后对二叉树进行遍历

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

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

相关文章

QOpenGLWidget视频画面上绘制矩形框

一、QPainter绘制 在QOpenGLWidget中可以绘制,并且和OpenGL的内容叠在一起。paintGL里面绘制完视频后,解锁资源,再用QPainter绘制矩形框。这种方式灵活性最好。 void VideoGLWidget::paintGL() {glClear(GL_COLOR_BUFFER_BIT);m_program.bi…

Linux系统加固笔记

检查口令为空的账户 判断依据:存在则不符合 特殊的shell a./bin/false:将用户的shell设置为/bin/false,用户会无法登录,并且不会有任何提示信息b./sbib/nologin:nologin会礼貌的向用户发送一条消息,并且拒绝用户登录…

【Go万字洗髓经】Golang中sync.Mutex的单机锁:实现原理与底层源码

本章目录 1. sync.Mutex锁的基本用法2. sync.Mutex的核心原理自旋到阻塞的升级过程自旋CAS 饥饿模式 3. sync.Mutex底层源码Mutex结构定义全局常量Mutex.Lock()方法第一次CAS加锁能够成功的前提是?竞态检测 Mutex.lockSlow()lockSlow的局部变量自旋空转state新值构造…

Django REST framework 源码剖析-认证器详解(Authentication)

Django REST framework 源码剖析-认证器详解(Authentication) 身份验证始终在视图的最开始运行,在权限和限制检查发生之前,以及在允许任何其他代码继续之前。request.user属性通常设置为contrib.auth包的user类的实例。request.auth属性用于任何其他身份…

TCP/IP三次握手的过程,为什么要3次?

一:过程 第一次(SYN): 客户端发送一个带有SYN标志的TCP报文段给服务器,设置SYN1,并携带初始序列号Seqx(随机值),进入SYN_SENT状态。等待服务器相应。 第二次&#xff08…

Centos6安装nerdctl容器运行时

Centos6安装nerdctl容器运行时 前言Centos6安装docker---失败--不可拉取镜像docker配置国内镜像加速 Centos6安装nerdctl-full容器管理工具为Centos6配置containerd服务开机自启动设置nerdctl自动补全 前言 本文写于2025年3月22日,因一些特殊业务需要用到Centos6Docker,但Cent…

登录验证码的接口实习,uuid,code.

UID是唯一标识的字符串,下面是百度百科关于UUID的定义: UUID是由一组32位数的16进制数字所构成,是故UUID理论上的总数为16322128,约等于3.4 x 10^38。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。 UUID的标准…

用fofa语法搜索漏洞

FOFA是一款非常强大的搜索引擎 关于对于fofa的描述是:FOFA(网络空间资产检索系统)是世界上数据覆盖更完整的IT设备搜索引擎,拥有全球联网IT设备更全的DNA信息。 探索全球互联网的资产信息,进行资产及漏洞影响范围分析…

20242817李臻《Linux⾼级编程实践》第6周

20242817李臻《Linux⾼级编程实践》第6周 一、AI对学习内容的总结 Linux进程间通信(IPC) 1. 进程间通信基本概念 作用: 数据传输:进程间传递数据(字节到兆字节级别)。共享数据:多个进程操作同一数据&…

深入解析SQL2API平台:数据交互革新者

在数字化转型持续深入的当下,企业对数据的高效利用与管理的需求愈发迫切。SQL2API平台应运而生,成为助力企业突破数据交互困境的有力工具,特别是它由麦聪软件基于DaaS(数据即服务)产品创新衍生而来,备受业界…

Java 中装饰者模式与策略模式在埋点系统中的应用

前言 在软件开发中,装饰者模式和策略模式是两种常用的设计模式,它们在特定的业务场景下能够发挥巨大的作用。本文将通过一个实际的埋点系统案例,探讨如何在 Java 中运用装饰者模式和策略模式,以及如何结合工厂方法模式来优化代码…

无人设备遥控器之调度自动化技术篇

一、技术原理 信息采集与处理: 通过传感器、仪表等设备采集无人设备的各种数据,如位置、速度、状态等。 将采集到的数据传输到调度自动化系统中进行处理和分析,以获取设备的实时状态。 系统建模与优化: 调度自动化系统会根据…

【AI】Orin Nano+ubuntu22.04上移植YoloV11,并使用DeepStream测试成功

【AI】郭老二博文之:AI学习目录汇总 1、准备工作 使用 sdk-manager 烧写 OrinNano, JetPack版本为6.0 DP,对应操作系统为:Ubuntu22.04 参见博客:【NVIDIA】Jetson Orin Nano系列:烧写Ubuntu22.04 2、安装 PyTorch 2.1 下载依赖 1)安装onnx pip install onnx -i h…

K8S学习之基础四十五:k8s中部署elasticsearch

k8s中部署elasticsearch 安装并启动nfs服务yum install nfs-utils -y systemctl start nfs systemctl enable nfs.service mkdir /data/v1 -p echo /data/v1 *(rw,no_root_squash) >> /etc/exports exports -arv systemctl restart nfs创建运行nfs-provisioner需要的sa账…

如何在 Windows 上安装并使用 Postman?

Postman 是一个功能强大的API测试工具,它可以帮助程序员更轻松地测试和调试 API。在本文中,我们将讨论如何在 Windows 上安装和使用 Postman。 Windows 如何安装和使用 Postman 教程?

Axure RP 9.0教程: 基于动态面板的元件跟随来实现【音量滑块】

文章目录 引言I 音量滑块的实现步骤添加底层边框添加覆盖层基于覆盖层创建动态面板添加滑块按钮设置滑块拖动效果引言 音量滑块在播放器类APP应用场景相对较广,例如调节视频的亮度、声音等等。 I 音量滑块的实现步骤 添加底层边框 在画布中添加一个矩形框:500 x 32,圆…

WPF 与 C# 开发深度剖析

一、引言 在当今的软件开发领域,Windows 平台依旧占据着重要的地位。而 WPF(Windows Presentation Foundation)作为微软推出的一款强大的用户界面(UI)框架,为开发者提供了丰富的功能和灵活的设计方式&…

好消息!软航文档控件(NTKO WebOffice)在Chrome 133版本上提示扩展已停用的解决方案

软航文档控件现有版本依赖Manifest V2扩展技术支持才能正常运行,然而这个扩展技术到2025年6月在Chrome高版本上就彻底不支持了,现在Chrome 133开始的版本已经开始弹出警告,必须手工开启扩展支持才能正常运行。那么如何解决这个技术难题呢&…

通过仿真确定抗积分饱和策略的最佳系数

通过仿真确定抗积分饱和策略的最佳系数(如PID参数 ( K_p, K_i, K_d ) 以及抗饱和参数 ( K_{\text{back}} )、积分限幅值等)是一个系统化的过程。以下是具体步骤和示例: — 1. 建立仿真模型 1.1 模型组成 被控对象:例如电机、温…

消息队列(Kafka及RocketMQ等对比联系)

目录 消息队列 一、为什么使用消息队列?消息队列有什么优点/缺点?介绍下Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优点缺点,如何取舍? 1.公司业务场景是什么,这个业务场景有什么挑战,如果不用MQ有什么麻…