数据结构与算法【树】

news2024/11/19 13:32:04

二叉树性质

满二叉树在这里插入图片描述

深度为k,有 2 k − 1 2^{k}-1 2k1个结点的二叉树,为满二叉树。

完全二叉树

完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。

二叉树的存储方式

包括链式存储和顺序存储
由于链式存储的二叉树更有利于我们理解,所以我们一般都是用链式存储二叉树。
所以大家要了解,用数组依然可以表示二叉树。

在这里插入图片描述

二叉树链式存储代码

struct TreeNode{
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x):val(x),left(NULL),right(NULL){}
};

二叉树的遍历方式

遍历方式分两类,四种

关于二叉树的遍历方式,首先从深度和广度来区分。

  1. 深度优先遍历:先往深走,遇到叶子节点再往回走。
  2. 广度优先遍历:一层一层地去遍历。
    这两种遍历是图论中最基本的两种遍历方式,后面在介绍图论的时候,还会介绍到。

那么我们进一步扩展深度优先遍历和广度优先遍历,才会有更为细致的遍历方式的区分:

  • 深度优先遍历
    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)
  • 广度优先遍历
    • 层次遍历(迭代法)
      在深度优先遍历中:有三个顺序,前中后序遍历,有同学总分不清这三个顺序,经常搞混,我这里教大家一个技巧。
      这里前中后,其实指的就是中间节点的遍历顺序,只要大家记住,前中后序指的就是中间节点的位置就可以了。看如下节点的遍历顺序,就可以发现中间节点的顺序就是所谓的遍历方式名称的由来:
  • 前(先)序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左右中

遍历方式的实现

最后再说一说二叉树中深度优先遍历和广度优先遍历的实现方式。我们做二叉树相关的题目,经常会使用递归的方式来实现深度优先遍历。
之前讲栈的时候,说过栈其实就是递归的一种实现结构,先进后出。也就就是说前中后序遍历的逻辑其实都是可以借助栈使用非递归的方式来实现。(通过栈的结构避免了递归操作)

而广度优先遍历的实现,一般借助队列来实现,这也是由于队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。

这里其实我们又了解了栈与队列的一个应用场景了。
具体的实现我们后面都会讲的,这里大家先要清楚这些理论基础。

二叉树与递归(二叉树的递归遍历)

说到二叉树,就不得不说递归,很多同学对递归都是又熟悉又陌生,递归的代码一般很简短,但每次都是一看就会,一写就废。

递归写不好的根本原因就是不成体系,没有递归方法论。通过二叉树的前中后序的递归写法,我们把递归方法论确定下来,进而应对复杂的递归题目。

首先,每次写递归算法,先确定三要素:

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
  3. **确定单层递归的逻辑:**确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

那三要素怎么切入,怎么找呢?
我们以前序遍历为例子,来找感觉!
1.确定递归函数的参数和返回值:因为我们要打印前序遍历节点的数值,因此参数里需要传入vector来放节点的数值,除了这一点就不需要再处理什么数据了,也不需要有返回值,所以递归函数返回类型就是void,代码如下:
(代码随想录点评:为什么要传入vector没讲清楚,另外代码还传入了节点本身,也很令人困惑?因为后面说的是除了vector不需要再处理什么数据了,也不需要有返回值,但是没提到传入TreeNode *cur的目的,但是我的猜想是,对树本身进行处理,肯定是要传入当前处理的树节点的指针的,至于为什么一定要用vector来放节点的数值,我想不通,希望后面会想通)

void traversal(TreeNode* cur, vector<int>& vec)

2.确定终止条件:在递归过程中,如何算递归结束?对于前序遍历,如果当前遍历的节点是空了,就说明递归结束了,所以如果当前遍历的节点是空,就直接return,代码如下:

if (cur == NULL) return;

3.确定单层递归的逻辑:前序遍历是中左右的顺序,因此单层递归的逻辑就是,先取中点节点的数值,(单层递归的逻辑这个概念讲的也不通!! 首先,什么是单层递归?如果重复调用单层递归实现递归的过程? 我的理解就是,每读到一个新数据,应当怎么处理这个数据,这个就是单层递归的数据处理逻辑!!!数据处理完成之后,就到了递归的逻辑了,单层递归本质上在数据处理完之后就结束了!!!后面就是递归的逻辑,例如这里递归下一个处理的数据是左子树的节点,因此对左子树进行递归,然后处理右子树,这里就继续对右子树进行递归!! 因此这里所说的单层递归,本质上就是一次数据处理过程+后面需要继续递归的数据!!!)

因此,代码如下

vec.push_back(cur->val);    // 中
traversal(cur->left, vec);  // 左
traversal(cur->right, vec); // 右

到这,我仍然看不懂,原因在于,我不知道TreeNode* cur的意义,以及vector &vec的意义,这就是代码随想录这一部分的败笔,读者很难理解!!!

然而,当读者继续往下读,读到整体代码的时候,就会恍然大悟:

class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        vec.push_back(cur->val);    // 中
        traversal(cur->left, vec);  // 左
        traversal(cur->right, vec); // 右
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result; //vector就是我们的遍历结果存储向量
        traversal(root, result);//遍历需要输入树的根节点
        return result;
    }
};

vector就是我们的遍历结果存储向量;遍历需要根据树逐步往下走,因此需要传入树根,并根据树根往下走,因此需要传入TreeNode* cur这参数。

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

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

相关文章

CSDN第22期周赛(记录一下,不是题解)

希望23年能收获一两本程序员杂志 前言 发现一个问题&#xff0c;codeblocks上编译没问题&#xff0c;在CSDN比赛时&#xff0c;会报错&#xff1a; 1&#xff0c;size()和length()属于unsigned int&#xff0c;所以与之比较大小或者赋值的 i, j 也要用unsigned int&#xf…

巧解 JavaScript 中的嵌套替换

网友 wys 提问&#xff1a;如何仅使用 JavaScript 支持的正则语法&#xff0c;将 <p> <table> <p> <p> </table> <table> <p> <p> </table> <p>中<table>...</table>之间的<p>都替换为<b…

C库函数:stdio.h

stdio.h C 标准库 – <stdio.h> | 菜鸟教程 (runoob.com) 下面是头文件 stdio.h 中定义的变量类型&#xff1a; 序号变量 & 描述1size_t 这是无符号整数类型&#xff0c;它是 sizeof 关键字的结果。2FILE 这是一个适合存储文件流信息的对象类型。3fpos_t 这是一个适…

组件的生命周期

一、组件的生命周期 1、组件的生命周期&#xff1a;至一个组件从 创建——>运行——>销毁的过程 2、声明周期函数&#xff1a;由Vue提供的内置函数&#xff0c;伴随组件生命周期按次序自动运行——>钩子函数 3、生命周期的阶段划分 &#xff08;1&#xff09;创建…

什么是链接?(动态链接库和静态链接库的对比)

什么是链接&#xff1f; 首先我们需要知道&#xff0c;一个源文件&#xff08;以.c为例&#xff09;是经过什么最后形成的一个可执行的文件&#xff08;windows下为.exe文件&#xff09;。 一个.c的源文件&#xff0c;要经历 1.预处理&#xff1a;头文件的展开替换 2.编译&…

skywalking解析-如何在idea中调试skywalking agent

当我从github上下载下来skywalking agent的代码后&#xff0c;面临的第一个问题就是如何调试。因为skywalking agent的运行模式与普通程序运行方式不一样&#xff0c;它是通过java agent方式运行的。本文接下来介绍如何在本地调试skywalking agent源码。 目录一、下载源码二、运…

leetcode_栈与队列

栈与队列栈与队列理论基础232.用栈实现队列225.用队列实现栈20.有效的括号1047.删除字符串中的所有相邻重复项150.逆波兰表达式求值239.滑动窗口最大值347.前k个高频元素栈与队列总结栈与队列理论基础 栈与队列理论基础 232.用栈实现队列 力扣题目链接 class MyQueue { pub…

Cadence PCB仿真使用Allegro PCB SI通过导入工艺文件配置层叠结构的方法图文教程

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,配置方法3,总结1,概述 本文简单介绍使用Allegro PCB SI通过导入工艺文件配置层叠结构的方法。 2,配置方法 第1步:打开待仿真的PCB文件,并确认软件为Allegro PCB SI 如果,打开软件不是Allegro PCB SI则…

【JavaScript】数组常用方法

冲突数组常用方法&#xff1a; 注&#xff1a; 以下方法都会对原数组进行改变&#xff1a; push&#xff1a;向数组后面追加元素&#xff0c;返回值是追加后的数组长度 pop&#xff1a;从数组后面删除元素&#xff0c;返回值是删除的元素内容 unshift:在数组前面添加元素&am…

CMMI之系统设计

系统设计&#xff08;System Design, SD&#xff09;是指设计软件系统的体系结构、用户界面、数据库、模块等&#xff0c;从而在需求与代码之间建立桥梁&#xff0c;指导开发人员去实现能满足用户需求的软件产品。系统设计过程域是SPP模型的重要组成部分。本规范阐述了系统设计…

第一章 Flink简介

Flink 系列教程传送门 第一章 Flink 简介 第二章 Flink 环境部署 第三章 Flink DataStream API 第四章 Flink 窗口和水位线 第五章 Flink Table API&SQL 第六章 新闻热搜实时分析系统 前言 流计算产品实时性有两个非常重要的实时性设计因素&#xff0c;一个是待计算…

文档智能(一):基于OpenCV的文档图像校正

文档智能(一)&#xff1a;基于OpenCV的文档图像校正 发表时间&#xff1a; 2023年1月7日创作地点&#xff1a;湖北省武汉市作者&#xff1a;ixy_com&[Aneerban Chakraborty]封面图片来源&#xff1a;DocTr 本文关键词&#xff1a;文档智能、文档图像校正、OpenCV、形态…

从零实现Dooring低代码印章组件

上一篇文章和大家分享了低代码平台组件间通信方案的几种实现:低代码平台组件间通信方案复盘今天继续和大家分享一下比较有意思的可视化印章组件的实现.你将收获低代码组件的基本设计模式印章组件的设计原理(canvas相关)如何快速将任意组件集成到低代码平台正文低代码组件的基本…

雷鸟X2:开启可量产全彩MicroLED光波导AR眼镜新起点

从最近的AR眼镜新品来看&#xff0c;采用MicroLED光波导方案已经成为了明显的趋势&#xff0c;可见业内对于光学的大方向还是非常统一的。不仅如此&#xff0c;各个厂商都拿出自己最优的方案来进行探索和验证&#xff0c;比如有的看重“极轻”、有的看重“视觉”、有的看重“价…

使用Jenkins一键打包部署 SpringBoot应用

一般而言&#xff0c;一个项目部署的由&#xff1a;拉取代码->构建->测试->打包->部署等过程组成&#xff0c;如果我们经常需要部署项目&#xff0c;特别是在微服务时代&#xff0c;服务特别多的情况下&#xff0c;不停的测试打包部署&#xff0c;那估计得有个人一…

数学:一夜读罢头飞雪

文章目录引子代数&#xff0c;几何与分析数学之美微积分形式的统一之美伽罗华群论的深刻之美几何的形体之美公理与定理集合论的公理欧几里得几何公理算术公理实数系的公理系统数学攀登的路径数学的符号系统希腊字母表物理与数学推荐的数学读物参考链接引子 贺新郎读史 人猿相揖…

【阶段二】Python数据分析数据可视化工具使用05篇:统计直方图、面积图与箱型图

本篇的思维导图: 统计直方图 统计直方图(histogram)形状类似柱形图,却有着与柱形图完全不同的含义。统计直方图涉及统计学的概念,首先要从数据中找出它的最大值和最小值,然后确定一个区间,使其包含全部测量数据,将区间分成若干个小区间,统计测量结果出现在各…

详细讲解Linux PCI驱动框架分析

说明&#xff1a; Kernel版本&#xff1a;4.14 ARM64处理器 使用工具&#xff1a;Source Insight 3.5&#xff0c; Visio 1. 概述 从本文开始&#xff0c;将会针对PCIe专题来展开&#xff0c;涉及的内容包括&#xff1a; PCI/PCIe总线硬件&#xff1b; Linux PCI驱动核心框…

通俗理解Platt scaling/Platt缩放/普拉特缩放

一、引言 最近在读论文的时候接触到Platt scaling&#xff0c;有点不理解这个概念。然后好奇心比较重&#xff0c;就看了一些科普&#xff0c;并追根溯源调查了一下Platt scaling。最终搞懂了这个概念&#xff0c;写个博客记录一下。中文翻译有看到&#xff1a;普拉特缩放&…

通信原理与MATLAB(十一):QAM的调制解调

目录1.QAM的调制原理2.QAM的解调原理3.QAM代码4.结果图5.特点1.QAM的调制原理 QAM调制原理如下图所示&#xff0c;基带码元波形经过串并转换分成I、Q两路&#xff0c;然后再经过电平转换(00转换成-1,01转换成-3,10转换成1,11转换成3)&#xff0c;再与对应的载波相乘&#xff0…