代码学习记录12

随想录日记part12

t i m e : time: time 2024.03.05



主要内容:今天的主要内容是了解二叉树的理论基础,并且熟练掌握如何递归和迭代遍历二叉树。

  • 理论基础
  • 递归遍历
  • 迭代遍历
  • 统一迭代


Topic1二叉树理论基础

1.二叉树的题目分类:请添加图片描述
2.二叉树的分类:
2.1 满二叉树:

如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。请添加图片描述

2.2 完全二叉树:

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

2.3 二叉搜索树:

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

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值
  • 它的左、右子树也分别为二叉排序树请添加图片描述
2.4 平衡二叉搜索树(AVL树):

它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。如图:请添加图片描述
C + + C++ C++ m a p 、 s e t 、 m u l t i m a p , m u l t i s e t map、set、multimap,multiset mapsetmultimapmultiset 的底层实现都是平衡二叉搜索树, m a p 、 s e t map、set mapset 的增删操作时间复杂度是 l o g n logn logn,注意 u n o r d e r e d _ m a p unordered\_map unordered_map u n o r d e r e d _ s e t unordered\_set unordered_set 底层实现是哈希表。

2.5 二叉树存储方式:

二叉树可以链式存储,也可以顺序存储。
链式存储如图:
请添加图片描述
顺序存储的方式如图:
请添加图片描述

用数组来存储二叉树如何遍历的呢
如果父节点的数组下标是 i i i,那么它的左孩子就是 i ∗ 2 + 1 i * 2 + 1 i2+1,右孩子就是 i ∗ 2 + 2 i * 2 + 2 i2+2

2.6二叉树的遍历方式:

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

  • 深度优先遍历:先往深走,遇到叶子节点再往回走。
  • 广度优先遍历:一层一层的去遍历。
2.6.1 深度优先遍历:
  • 前序遍历(递归法,迭代法)
  • 中序遍历(递归法,迭代法)
  • 后序遍历(递归法,迭代法)
    请添加图片描述
2.6.2 广度优先遍历:
  • 层次遍历(迭代法)
2.7二叉树的节点定义:
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}


Topic2二叉树的递归遍历

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

java实现的代码如下:

class Solution {//递归前序遍历
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> tem=new ArrayList<Integer>();
        Traversal(root,tem);
        return tem;
    }
    void Traversal(TreeNode root,List<Integer> result){
        if(root==null)return;
        result.add(root.val);//中
        Traversal(root.left,result);//左
        Traversal(root.right,result);//右
    }
}
class Solution {//递归中序遍历
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> tem=new ArrayList<Integer>();
        Traversal(root,tem);
        return tem;
    }
    void Traversal(TreeNode root,List<Integer> result){
        if(root==null)return;
        Traversal(root.left,result);//左
        result.add(root.val);//中
        Traversal(root.right,result);//右
    }
}

class Solution {//递归后序遍历
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> tem=new ArrayList<Integer>();
        Traversal(root,tem);
        return tem;
    }
    void Traversal(TreeNode root,List<Integer> result){
        if(root==null)return;
        Traversal(root.left,result);//左
        Traversal(root.right,result);//右
        result.add(root.val);//中
    }
}


Topic3二叉树的迭代遍历

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

  • 1.前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。动画如下:请添加图片描述
class Solution {// 递归前序遍历
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode tem = stack.pop();
            result.add(tem.val);//中
            if (tem.right != null)//右孩子入栈
                stack.push(tem.right);
            if (tem.left != null)//左孩子入栈
                stack.push(tem.left);
        }
        return result;
    }

  • 2.中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进 r e s u l t result result 数组中),这就造成了处理顺序和访问顺序是不一致的。那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。动画如下:请添加图片描述
class Solution {// 递归中序遍历
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (!stack.isEmpty() || cur != null) {
            if(cur!=null){
                stack.push(cur);
                cur=cur.left;
            }else{
                cur=stack.pop();
                result.add(cur.val);
                cur=cur.right;
            }
        }
        return result;
    }

  • 3.后序遍历只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转 r e s u l t result result 数组,输出的结果顺序就是左右中了,如下图:请添加图片描述
class Solution {// 递归后序遍历
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode tem = stack.pop();
            result.add(tem.val);//中
            if (tem.left != null)//左孩子入栈
                stack.push(tem.left); 
            if (tem.right != null)//右孩子入栈
                stack.push(tem.right);
        }
        Collections.reverse(result);
        return result;
    }
}


Topic4二叉树的统一迭代法

三种遍历方式,使用迭代法是可以写出统一风格的代码,统一写法如下:

上面的方法无法解决同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况。将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记:就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。
详细看如下代码:

class Solution {//先序
   public List<Integer> preorderTraversal(TreeNode root) {
       List<Integer> result = new LinkedList<>();
       Stack<TreeNode> st = new Stack<>();
       if (root != null) st.push(root);
       while (!st.empty()) {
           TreeNode node = st.peek();
           if (node != null) {
               st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
               if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)
               if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)
               st.push(node);                          // 添加中节点
               st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
               
           } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
               st.pop();           // 将空节点弹出
               node = st.peek();    // 重新取出栈中元素
               st.pop();
               result.add(node.val); // 加入到结果集
           }
       }
       return result;
   }
}
class Solution {//中序
public List<Integer> inorderTraversal(TreeNode root) {
       List<Integer> result = new LinkedList<>();
   Stack<TreeNode> st = new Stack<>();
   if (root != null) st.push(root);
   while (!st.empty()) {
       TreeNode node = st.peek();
       if (node != null) {
           st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
           if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)
           st.push(node);                          // 添加中节点
           st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。

           if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)
       } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
           st.pop();           // 将空节点弹出
           node = st.peek();    // 重新取出栈中元素
           st.pop();
           result.add(node.val); // 加入到结果集
       }
   }
   return result;
}
}
class Solution {//后序
  public List<Integer> postorderTraversal(TreeNode root) {
       List<Integer> result = new LinkedList<>();
       Stack<TreeNode> st = new Stack<>();
       if (root != null) st.push(root);
       while (!st.empty()) {
           TreeNode node = st.peek();
           if (node != null) {
               st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
               st.push(node);                          // 添加中节点
               st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
               if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)
               if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)         
                              
           } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
               st.pop();           // 将空节点弹出
               node = st.peek();    // 重新取出栈中元素
               st.pop();
               result.add(node.val); // 加入到结果集
           }
       }
       return result;
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu20.04设置docker容器开机自启动

ubuntu20.04设置docker容器开机自启动 1 docker自动启动2 容器设置自动启动3 容器自启动失败处理 1 docker自动启动 &#xff08;1&#xff09;查看已启动的服务 $ sudo systemctl list-units --typeservice此命令会列出所有当前加载的服务单元。默认情况下&#xff0c;此命令…

【QT】窗口的大小标题图标设置

窗口的大小标题图标设置 添加一个新的类 创建完成&#xff0c;根据上一节最后的在总结&#xff0c;做个测试&#xff1a; #include "mybutton.h" #include <QDebug>//打印&#xff0c;标准输出 MyButton::MyButton(QWidget *parent) : QPushButton(parent) { …

基于springboot的新闻推荐系统论文

基于springbootvue的新闻推荐系统 摘要 随着信息互联网购物的飞速发展&#xff0c;国内放开了自媒体的政策&#xff0c;一般企业都开始开发属于自己内容分发平台的网站。本文介绍了新闻推荐系统的开发全过程。通过分析企业对于新闻推荐系统的需求&#xff0c;创建了一个计算机…

09. Nginx进阶-Rewrite

简介 什么是rewrite&#xff1f; rewrite即URL重写&#xff0c;主要实现URL地址重写&#xff0c;以及重定向。 就是把插入web的请求重定向到其他URL的过程。 rewrite使用场景 URL地址调整 例如用户访问wang.mingqu.com将其跳转到ming.mingqu.com。 或者当用户通过http的方…

计算机丢失msvcp140_1.dll怎样修复,分享五种有效的解决方法

当计算机系统中msvcp140_1.dll文件发生丢失时&#xff0c;可能会引发一系列运行问题&#xff0c;具体表现形式多种多样。首先&#xff0c;由于msvcp140_1.dll是Microsoft Visual C Redistributable Package的重要组成部分&#xff0c;它的缺失将直接影响到依赖这一库的各类应用…

VLAN虚拟局域网络

VLAN的概念和配置: http://t.csdnimg.cn/g39F7http://t.csdnimg.cn/g39F7 VLAN中常见的接口类型 http://t.csdnimg.cn/mhahzhttp://t.csdnimg.cn/mhahz 实验&#xff1a;

KCMY1VUG12T8更大容量、更快企业级SSD NVMe PCIe

近年来&#xff0c;随着SSD固态硬盘技术的不断成熟和价格的进一步下降&#xff0c;SSD逐渐普及到市场。越来越多的企业、个人开始采用SSD&#xff0c;用户体验得到了显著提升。 最近感觉无论国内国外的客户需求均发生一些变化&#xff0c;具体主要体现在3个方面。 1、容量持续…

总结:直径测量的发展历程!在线测径仪已成主要方式!

测量在生活、生产和科学探究中扮演着至关重要的角色。从古至今&#xff0c;人们对测量的探索从未停止。而外径作为一种基础的几何尺寸&#xff0c;其测量也经过了多代发展&#xff0c;直到至今被广泛应用到工业生产中的在线测径仪。本文就来介绍一下外径测量的发展历程&#xf…

如何用Elementor创建WordPress会员网站

在下面的文章中&#xff0c;我们将向您展示如何使用Elementor和MemberPress在WordPress中轻松构建会员网站。这篇文章将涵盖WordPress会员网站设置过程、会员资格和受保护内容创建、重要页面和登录表单设计、电子邮件通知管理、报告等。 目录 什么是WordPress会员网站&#x…

5G智能制造热力工厂数字孪生可视化平台,推进热力行业数字化转型

5G智能制造热力工厂数字孪生可视化平台&#xff0c;推进热力行业数字化转型。在当今这个信息化、数字化的时代&#xff0c;热力生产行业也迎来了转型的关键时刻。为了提升生产效率、降低成本、提高产品质量&#xff0c;越来越多的热力生产企业开始探索数字化转型之路。而5G智能…

短视频账号矩阵系统开发3年----技术环境外部的动荡

前言&#xff1a; 目前市面上开发短视频账号矩阵系统的源头公司已经不多了吧&#xff0c;或者说都已经被市场被官方平台的政策影响的不做了吧&#xff0c;做了3年多的矩阵系统开发到现在真的是心里没有安全感吧&#xff0c;抖音的代发布接口&#xff0c;21年大封一次&#xff…

机械五要素手持气象站的应用

TH-SQ5在数字化和智能化的时代背景下&#xff0c;气象监测技术正日益成为众多行业不可或缺的利器。其中&#xff0c;机械五要素手持气象站以其便携性、实时性和多功能性受到了广泛关注。下面讲解一下手持气象站是什么以及应用&#xff1a; 一、机械五要素手持气象站概述 机械五…

Unity2023.1.19_ECS_DOTS

Unity2023.1.19_ECS_DOTS 盲学-盲目的学习&#xff1a; 懒着自己整理就看看别人整理的吧&#xff0c;整合一下逻辑通了不少&#xff1a; DOTS/data oriented technology stack-面向数据的技术栈 ECS/Entities-Component-System Unity-Entities包 Entities提供ECS架构面向数…

指针篇章-(2)

学习流程图 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————…

Domain Adaptation Vs. Prompt-Tuning:能否用域自适应解决大模型提示学习问题?

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 作者简介 李江梦&#xff0c;中国科学院软件研究所天基综合信息系统全国重点实验室助理研究员 论文简介 今天介绍的是被机器学习领域顶级学术会议ICLR 2024接收的论文&#xff1a;BayesPrompt: Prompting Large…

微信公众号里的视频怎么提取出来,30秒轻松下载视频方法!

在微信公众号中&#xff0c;我们常常能发现许多精彩纷呈的视频内容&#xff0c;这些视频或许让我们受益匪浅&#xff0c;或许让我们捧腹大笑。然而&#xff0c;微信平台并没有提供直接的下载功能&#xff0c;这让许多用户感到困扰。 别担心&#xff0c;今天我们就来揭秘如何将…

低密度奇偶校验码LDPC(九)——QC-LDPC译码器FPGA全并行设计

往期博文 低密度奇偶校验码LDPC&#xff08;一&#xff09;——概述_什么是gallager构造-CSDN博客 低密度奇偶校验码LDPC&#xff08;二&#xff09;——LDPC编码方法-CSDN博客 低密度奇偶校验码LDPC&#xff08;三&#xff09;——QC-LDPC码概述-CSDN博客 低密度奇偶校验码…

flink重温笔记(十):Flink 高级 API 开发——flink 四大基石之 State(涉及Checkpoint)

Flink学习笔记 前言&#xff1a;今天是学习 flink 的第 10 天啦&#xff01;学习了 flink 四大基石之 State &#xff08;状态&#xff09;&#xff0c;主要是解决大数据领域增量计算的效果&#xff0c;能够保存已经计算过的结果数据状态&#xff01;重点学习了 state 的类型划…

IISExpress 跨域cookie的奇怪问题

测试环境 WIN10&#xff0c;IIS 10&#xff0c;IISExpress 10&#xff0c;Chrome 120&#xff0c;Microsoft Edge 114 网站A 端口7001 只有1个Default.aspx&#xff0c;无前端代码。逻辑很简单&#xff0c;SetCookie用来把客户端传过来的值写入到cookie中&#xff0c;GetCoo…

RK DVP NVP6158配置 学习

NVP6158简介 NVP6158C是一款4通道通用RX&#xff0c;提供高质量图像的芯片。它接受来自摄像机和其他视频信号的独立4通道通用输入来源。它将4通道通用1M至8M 7.5P视频格式数字化并解码为代表8位ITU-R BT.656/1120 4:2:2格式的数字分量视频&#xff0c;并将单独的BT.601格式与27…