代码随想录算法训练营43期 | Day 13 —— 二叉树part01

news2024/12/22 1:20:17

代码随想录算法训练营

  • 二叉树理论基础
    • 二叉树的种类
      • 1. 满二叉树
      • 2. 完全二叉数
      • 3. 二叉搜索树
      • 3. 平衡二叉搜索树
    • 二叉树的存储方式
    • 二叉树遍历方式
    • 二叉树的定义
  • 二叉树的递归遍历
    • 144.前序遍历
    • 145.后序遍历
    • 94.中序遍历
  • 二叉树迭代遍历
    • 前序遍历(迭代法)
    • 后序遍历(迭代法)
    • 中序遍历(迭代法)
  • 二叉树层序遍历(广度优先搜索)

二叉树理论基础

二叉树的种类

1. 满二叉树

满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。

性质:深度为K ,节点数: 2^k-1
在这里插入图片描述

2. 完全二叉数

在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。
底层从左到右是连续的。
在这里插入图片描述

3. 二叉搜索树

二叉搜索树是有数值的,二叉搜索树是一个有序树。

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉排序树
    在这里插入图片描述

3. 平衡二叉搜索树

又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
在这里插入图片描述

C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn,注意我这里没有说unordered_map、unordered_set,unordered_map、unordered_set底层实现是哈希表。

二叉树的存储方式

二叉树可以链式存储,也可以顺序存储。
那么链式存储方式就用指针, 顺序存储的方式就是用数组。
链式存储:
在这里插入图片描述
顺序存储:

在这里插入图片描述

用数组来存储二叉树如何遍历的呢?
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
但是用链式表示的二叉树,更有利于我们理解,所以一般我们都是用链式存储二叉树。

二叉树遍历方式

二叉树主要有两种遍历方式:

  1. 深度优先遍历:先往深走,遇到叶子节点再往回走。(前中后序遍历)——递归、迭代法
  2. 广度优先遍历:一层一层的去遍历。(层序遍历)——迭代法

前序遍历:中左右
中序遍历:左中右
后序遍历:左右中

在这里插入图片描述

二叉树的定义

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

二叉树的递归遍历

递归三步走:

  1. 确定递归函数的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑

144.前序遍历

中 左 右

 //构造递归函数,确定传入的参数,前序遍历,顺序:中左右,传入节点,
    void preorder(TreeNode* root, vector<int>& result)
    {
        if(root==nullptr) return;
        //中
        result.push_back(root->val);
        //左
        preorder(root->left,result);
        //右
        preorder(root->right, result);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        preorder(root, result);
        return result;
    }

145.后序遍历

//递归函数
    void backorder(TreeNode* root, vector<int>& result)
    {
        //1. 定义递归终止条件
        if(root==nullptr) return;
        //左 右  中
        backorder(root->left, result);
        backorder(root->right, result);
        result.push_back(root->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        //数组 ,存储结果
        vector<int> result;
        backorder(root, result);
        return result;
    }

94.中序遍历

 //中序遍历
    void midorder(TreeNode* cur, vector<int>& result)
    {
        //递归结束
        if(cur==nullptr) return;
        //左
        midorder(cur->left,result);
        //中
        result.push_back(cur->val);
        //右
        midorder(cur->right, result);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        midorder(root, result);
        return result;
    }

二叉树迭代遍历

递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
用栈实现前中后序遍历

前序遍历(迭代法)

 vector<int> preorderTraversal(TreeNode* root) {
        //迭代法实现前序遍历
        //数组 result存储 遍历结果
        vector<int> result;
        //栈模拟实现递归过程,栈的数据类型是二叉树节点(指针)
        stack<TreeNode*> st;
        if(root==nullptr) return result;
        //root根节点入栈
        st.push(root);
        //中 左 右 
        while(!st.empty())
        {
            //取出栈中元素,将其放入到result数组中
            TreeNode* cur = st.top();
            st.pop();
            result.push_back(cur->val);
            //先右后左,出栈顺序为左、右,符合前序遍历逻辑
            if(cur->right) st.push(cur->right);
            if(cur->left)  st.push(cur->left);
        }
        return result;
    }

后序遍历(迭代法)

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        //前序遍历 中左右 -> 中右左-> 翻转reverse -> 左右中
        vector<int> result;
        stack<TreeNode*> st;
        //root为nullptr 返回result
        if(root==nullptr) return result;
        st.push(root);
        //循环遍历
        while(!st.empty())
        {
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            
            if(node->left)  st.push(node->left);
            if(node->right) st.push(node->right);
            
        }
        reverse(result.begin(), result.end());
        return result;
    }
};

中序遍历(迭代法)

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) { // 指针来访问节点,访问到最底层
                st.push(cur); // 将访问的节点放进栈
                cur = cur->left;                // 左
            } else {
                cur = st.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
                st.pop();
                result.push_back(cur->val);     // 中
                cur = cur->right;               // 右
            }
        }
        return result;
    }
};

二叉树层序遍历(广度优先搜索)

解题思路:

需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

流程:

  1. 判断根节点是否为空,否则存入队列中;
  2. 遍历的终止条件,queue中为空,则停止遍历;
  3. 控制每一层的弹出节点的个数,size存当前queue中的元素,当size=1时,则为第一层,循环条件为一次;将queue中节点弹出并存放到vector一维数组中;
  4. 向下移动节点,根节点的左节点和右节点入队;
  5. 得到当前队列的size = 2;循环终止2次;弹出左节点,并存放到一维数组中,并将左节点的左子节点和右子节点存放到队列中;第二次循环,弹出右节点,并将右左子节点和右右子节点插入队列中;
  6. 获得当前队列的长度为size = 4;弹出队列中元素存放到一维数组中;
  7. 最后将一位数组结果保存到二维数组中,返回result;

核心需要记录size,记录的是本层的需要弹出的节点数量

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
        //存储二维数组,最终结果
        vector<vector<int>> result;
        //1 判断root不为空,将第一个节点加入到队列中
        if(root!=nullptr) que.push(root);
        //2 遍历终止条件,队列中没有元素,!que.empty();
        while(!que.empty())
        {
            // 3 控制当前节点数量 size ,控制弹出元素的数量
            int size = que.size();
            // 4 定义一维数组,存放队列中元素,最终结果需要用二维数组显示
            vector<int> vec;
            //5 遍历队列
            for(int i = 0; i<size;i++)
            {
                // 获取队列中的元素,弹出
                TreeNode* node = que.front();
                que.pop();
                // 存储结果,记录完本层结果
                vec.push_back(node->val);
                //节点移到下一层
                if(node->left)  que.push(node->left);
                if(node->right) que.push(node->right);
            }
            //一维数组保存后
            result.push_back(vec);
        }
        return result;
    }
};

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

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

相关文章

实战项目:贪吃蛇游戏的实现(下)

前言 今天我们将继续贪吃蛇游戏的实现&#xff0c;紧接上期我们已经实现了贪吃蛇游戏的大部分基础知识&#xff0c;我们上期主要是学习了Windows系统的API函数,并实现了大部分的贪吃蛇设计&#xff0c;那这期我们将完成剩余的设计部分&#xff0c;并完成代码的实现。 好&…

UEC++学习(十六)变量添加中文注释、ui设置中文文本

&#xff08;一&#xff09;变量添加中文注释 在C 项目中创建变量&#xff0c;并在蓝图中显示变量的英文名同时附带中文注释&#xff0c;可以使用UPROPERTY 的 ToolTip 元数据属性来实现 UPROPERTY(EditAnywhere, meta (ToolTip "弹夹最大容量"))int32 MagCapacit…

目标检测算法,Yolov7本地化部署标注、训练(二)

安全帽检测、口罩检测、行为检测、目标物体检测&#xff0c;随着深度学习和计算机视觉技术的不断发展&#xff0c;目标检测成为了研究热点之一。YOLOv7作为YOLO系列的新成员&#xff0c;以其高效和准确的性能受到了广泛关注。本文将介绍如何在本地部署并利用YOLOv7完成目标检测…

StormBamboo 入侵 ISP 并滥用不安全的软件更新机制

关键要点 StormBamboo 成功入侵了一家互联网服务提供商 (ISP)&#xff0c;以毒害目标组织的 DNS 响应。不安全的软件更新机制旨在在运行 macOS 和 Windows 的受害者机器上秘密安装恶意软件。StormBamboo 部署的恶意软件包括 MACMA 恶意软件的新变种。对 MACMA 最新版本的分析表…

Python学习入门实验

&#xff08;1&#xff09;掌握python数字类型的使用方法 &#xff08;2&#xff09;掌握将数学表达式转换成python语言表达式的方法及注意 &#xff08;3&#xff09;掌握有关运算符号的特殊要求 &#xff08;4&#xff09;掌握输入、输出函数的使用方法 &#xff08;5&am…

Python与netCDF数据之全面解析空间偏相关分析详解

概要 在气象学、海洋学、环境科学等领域,netCDF(Network Common Data Form)是一种常用的数据格式,用于存储和共享多维科学数据。偏相关分析(Partial Correlation Analysis)是一种统计方法,用于研究多个变量之间的关系,同时控制其他变量的影响。本文将详细介绍如何使用…

VTK-vtkStructuredGrid学习

vtkStructuredGrid是具有规则拓扑和不规则几何的数据集。可以理解为单元格顺序沿着坐标轴排列&#xff0c;但是每个单元格可以不一样。看了很多文字解释&#xff0c;感觉不清楚&#xff0c;直接用图解验证&#xff1a; 1.使用CAD随意绘制个网格草图 2.获取这些点信息&#xff…

Sealos 就是小团队的神器

作者&#xff1a;阳明。Kubernetes 布道师&#xff0c;公众号 K8s 技术圈主理人 最近我们新开发了一个项目 fastclass.cn&#xff0c;这个项目是一个独立开发者的学习网站&#xff0c;我们的目标是帮助你使用 Figma、Python、Golang、React、VUE、Flutter、ChatGPT 等设计构建真…

【linux】linux中如何通过systemctl来创建和管理服务

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

【网络】从零认识IPv4

目录 IP地址定义 网络标识和主机标识 子网掩码 IPv4地址的分类 全局地址和私有地址 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 IP地址定义 IP是网络中每台设备的唯一标识符&#xff0c;用于识别和定位计算机、服务器、路由器等设备&#xff0c;以便它们能够在网络上…

VictoriaMetrics快速入门

文章目录 Multitenancy集群部署启动vmstorage服务启动vminsert服务启动 vmselect服务 配置使用集群大小调整和可伸缩性grafana展示参考资料 VictoriaMetrics是快速&#xff0c;经济高效且可扩展的时间序列数据库。它可以用作Prometheus的长期远程存储。 VictoriaMetrics集群包含…

鸿蒙开发5.0【同页面内的点击操作响应时延问题】分析思路案例

1. 场景导入 同页面内点击操作时延是指&#xff0c;应用内手指点击从离开屏幕开始&#xff0c;到页面发生变化的时间。常见场景包括点击后界面元素变化&#xff0c;弹出弹窗或者loading动画等场景。 2. 性能指标 2.1 性能衡量起始点介绍 1.点击操作响应时延的性能衡量的起点…

GitLab-CI/CD指南

由于公司没有运维&#xff0c;写go服务时各个环境编译部署还是略显麻烦&#xff0c;由于代码管理使用的是 gitlab&#xff0c;所以决定使用 gitlab 自带的 CI/CD 来做自动编译和部署&#xff0c;这样每次提交代码以后就可以自动部署到服务器上了。 gitlab 本身只有 CI/CD 的接…

金蝶云星辰V1与旺店通·企业版对接集成采购入库单查询(列表+详情)连通创建其他入库单(其他)

金蝶云星辰V1与旺店通企业版对接集成采购入库单查询&#xff08;列表详情&#xff09;连通创建其他入库单(其他) 接入系统&#xff1a;金蝶云星辰V1 金蝶云星辰基于金蝶云苍穹云原生PaaS平台构建&#xff0c;聚焦小型企业在线经营和数字化管理&#xff0c;提供财务云、税务云、…

操作系统中的进程:深入解析与理解

文章目录 一、什么是进程&#xff1f;&#x1f914;二、进程的特性 &#x1f31f;三、进程的组成 &#x1f9e9;四、进程的状态与转换 &#x1f504;&#x1f500;五、进程的调度与管理 &#x1f527;&#x1f500;六、代码示例&#xff08;C&#xff09;创建进程进程等待&…

scanf中%c前加不加空格的区别

%c前加空格可以让scanf跳过空白字符&#xff08;如空格、制表符、换行符等&#xff09;&#xff0c;直接读取非空白字符。如果不加空格就会读取空白字符。 可以用两段测试客官有无慧根的程序来说明这个问题&#xff0c;测试代码如下&#xff1a; #include <stdio.h> in…

Ubuntu22.04安卓编译环境搭建及so库编译

1.配置Android-ARM64开发环境工具链: vim ~/.profile 或者 ~/.bashrc 或者 /etc/profile 编辑环境变量文件 输入下面内容 export CROSS_TRIPLE=aarch64-linux-android export CROSS_ROOT=/usr/${CROSS_TRIPLE} export ANDROID_NDK=${CROSS_ROOT} export AS=${CROSS_ROOT}…

【人工智能】数据集合集!

本文将为您介绍10个经典、热门的数据集&#xff0c;希望对您在选择适合的数据集时有所帮助。 点击蓝字 关注我们 1 Habitat Platform 发布方&#xff1a; Facebook AI Research西蒙菲莎大学佐治亚理工学院Facebook Reality LabsIntel LabsUniversity of California, Berkeley…

1- 关键字static

文章目录 1 前言2 static修饰局部变量2.1 局部变量无static修饰2.2 局部变量有static修饰 3 static修饰全局变量 1 前言 在C语言中&#xff0c;static是用来修饰变量和函数的&#xff1a; 修饰局部变量 - 称为静态局部变量修饰全局变量 - 称为静态全局变量修饰函数 - 称为静态…

django空巢老人志愿服务系统-计算机毕业设计源码58726

摘 要 随着社会老龄化问题日益突出&#xff0c;空巢老人群体的关注和关怀日益重要。本研究设计并实现了基于Python的空巢老人志愿服务系统&#xff0c;旨在利用技术手段提供更多关爱和支持给空巢老人群体。 该系统结合Python编程语言的灵活性和易用性&#xff0c;实现了慈善捐赠…