树的一些经典 Oj题 讲解

news2024/11/25 12:40:16

关于树的遍历

先序遍历

我们知道 树的遍历有 前序遍历 中序遍历 后序遍历 然后我们如果用递归的方式去解决,对我们来说应该是轻而易举的吧!那我们今天要讲用迭代(非递归)实现 树的相关遍历
首先呢 我们得知道 迭代解法 本质上也是在模拟递归,因为递归的过程中使用了系统栈,所以我们在迭代的时候也要用Stack来模拟系统栈。
我们要一开始就要创建一个顺序表接收打印的值 最终程序结束输出出来。
首先我们要创建一个栈来存放结点 ,首先我们就要打印根节点的值 ,此时栈中的内容为null,所以我们优先将头结点puth进去栈,然后打印。其实就很好理解 如果树为空 直接就返回了 。

在这里插入图片描述
我们首先从根节点开始遍历 只要节点不为空 就进入循环 就push 进栈 再打印 再去遍历左子树 ,直到左子树为空,就进不来循环 了 我们就要从栈中弹出元素,去遍历他的右子树 但是现在只有一层循环 不能够继续进入回到上面再进入左子树的循环 那怎么办呢 我们就可以再加一层循环在最外面包着他们 判断条件依然是节点不为空 ,但是这样就解决了吗 当然还没有 你去遍历右子树 肯定会最后右孩子结点为空 又怎么返回循环呢 此时已经节点为空了 进不去循环了 但是还没遍历结束, 该怎么办呢 现在栈还没空 也是一个判断条件 我们就可以再外层循环加一个条件栈不为空

最终的实现你们可以参考代码:

public List<Integer> preorderTraversal(TreeNode root) {
        //先定义一个顺序表去接收
        List<Integer> list = new ArrayList<>();
        if(root == null){
            return list;
        }

        //用链表去实现一个栈
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()){
        while(cur != null){
            list.add(cur.val);
            stack.push(cur);
            cur = cur.left;
        }
        cur = stack.pop();
        cur = cur.right;
        }
        return list;
    }

根据代码去分析上面那棵二叉树 我们就可以输出他的二叉树遍历序列。

中序遍历

通过上面的先序遍历 ,我们可以知道大概的思路 。其实中序遍历迭代(非递归)实现 和先序遍历的实现其实差不太多 就输出的位置换一下 因为是 左 根 右 ,所以我们先去遍历完左子树 ,push进栈。 左子树为空 的时候再从栈中弹出元素 打印元素。
具体代码实现如下:

 public List<Integer> inorderTraversal(TreeNode root) {
 //先定义一个顺序表去接收
        List<Integer> list = new ArrayList<>();
        if(root == null){
            return list;
        }

        //用链表去实现一个栈
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()){
        while(cur != null){
            
            stack.push(cur);
            cur = cur.left;
        }
        cur = stack.pop();
        list.add(cur.val);
        cur = cur.right;
        }
        return list;
    }

写到这里 大家是不是觉得 so easy 后序遍历 想直接开敲 ,但是这里提醒大家 后序遍历 没有前序和中序那样简单了 后序会涉及到一个记录结点。 下面我们来分析一下

后序遍历

大体思路和前面两种一样 还是利用栈来实现 因为 后序遍历是 左 右 根
在这里插入图片描述
首先我们先用cur遍历左子树,只要左子树不为空 , 就push进栈 如果左子树为空的话 怎么办呢 ? 我们要从栈中弹出元素吗 那肯定不行啊 因为你还得判断后面有没有右子树 ,所以你只能peek出来看一下。 如果有右子树 我们则让cur = peek出来的节点的右子树,如果右子树为空呢 我们是不是可以pop出栈并且打印出来 。然后现在cur是为空的 进不去循环 然后我们又peek一下栈顶元素 判断他右子树为不为空 但是你会发现现在代码死循环了 他还是会打印刚才的打印过的节点的值 那怎么办呢 ? 很简单 我们定义一个节点prev 来记录一下打印过的结点 。只要peek出来的元素的右孩子 是prev 说明打印过 就直接将他弹出来 打印 所以 现在我们有两个条件可以直接弹出来 打印 然后记录一下, 就是当右孩子为空 或者右孩子是已经打印过的结点 就可以弹出栈顶的元素打印 因为该元素已经是最后一次用了 。
下面我们直接上代码:

 public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null){
            return list;
        }
        //创建一个栈
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode prev = null;//用来记录打印过的结点
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            //只能拿出来看一下 不能弹出来
            TreeNode top = stack.peek();
            if(top.right == null ||top.right == prev ){ 
    //这里代码会出现死循环  因为会一直在那个结点 所以我们要记录的节点 加一个判断条件
                stack.pop();
                list.add(top.val);
                prev = top;
            }else{
                cur = top.right;
            }
        }
        return list;
    }

二叉树转字符串

题目是这样描述的 给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造成的字符串。

空节点 用一对空括号“()”表示,转化后可以省略所有不影响字符串与原始的二叉树直接的一对一关系的空括号对。

相信大家读完题目会觉得很懵 ,其实题目的情况分为4种 :
1.左右子树都有 则需要 这样加括号:root((left),(right));
2、只有右子树 :root((), (right));
3、只有左子树:root((right));
4、叶子节点 :root;

总的来说 不管有没有左子树 ,只要有右子树 左子树都要加括号。
下面来看几个示例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看完示例 相信大家已经知道思路了 我们直接上代码:

 StringBuilder sb = new StringBuilder();
    public String tree2str(TreeNode root) {
        preoderTraveral(root);
        return sb.toString();
    }
    private void preoderTraveral(TreeNode root){
        if(root == null){
            return;
        }
        sb.append(root.val);
        if(root.left != null || root.right != null){
            sb.append("(");
            preoderTraveral(root.left);
            sb.append(")");
            if(root.right != null){
                sb.append("(");
                preoderTraveral(root.right);
                sb.append(")");
            }
        }
    }

看完上面四道题目 相信大家已经想去跃跃欲试了 下面我把题目的链接放在下面

迭代实现前序遍历

迭代实现中序遍历

迭代实现后序遍历

根据二叉树创建字符串

其实关于树的OJ题有很多 感兴趣的可以去力扣或者牛客网上 查找做一下 。

最后感谢大家的浏览 !!!

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

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

相关文章

微信小程序(九)轮播图

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1.轮播容器的基本属性 2.轮播图片的尺寸处理 index.wxml <view class"navs"><text class"active">精选</text><text>手机</text><text>食品</text><…

第6章 现代通信技术

文章目录 6.1 图像与多媒体通信6.1.1 图像通信6.1.2 多媒体通信技术1、多媒体通信概念2、多媒体通信的组成3、多媒体通信的业务分类4、实用化的多媒体通信系统类型5、多媒体通信应用系统&#xff08;1&#xff09;多媒体会议电视系统&#xff08;2&#xff09;IPTV 6.2 移动通信…

C++——函数

1&#xff0c;概述 函数的作用&#xff1a;将一段经常使用的代码封装起来&#xff0c;减少重复代码 一个较大的程序&#xff0c;一般分为若干个程序块&#xff0c;每个模块实现特定的功能。 2&#xff0c;函数的定义 函数的定义一般主要有五个步骤&#xff1a; 1&#xff…

69.使用Go标准库compress/gzip压缩数据存入Redis避免BigKey

文章目录 一&#xff1a;简介二&#xff1a;Go标准库compress/gzip包介绍ConstantsVariablestype Headertype Reader 三&#xff1a;代码实践1、压缩与解压工具包2、单元测试3、为何压缩后还要用base64编码 代码地址&#xff1a; https://gitee.com/lymgoforIT/golang-trick/t…

USB-C接口给显示器带来怎样的变化?

随着科技的不断发展&#xff0c;Type-C接口已经成为现代电子设备中常见的接口标准。它不仅可以提供高速的数据传输&#xff0c;还可以实现快速充电和视频传输等功能。因此&#xff0c;使用Type-C接口的显示器方案也受到了广泛的关注。本文将介绍Type-C接口显示器的优势、应用场…

基于C++11的数据库连接池【C++/数据库/多线程/MySQL】

一、概述 概述&#xff1a;数据库连接池可提前把多个数据库连接建立起来&#xff0c;然后把它放到一个池子里边&#xff0c;就是放到一个容器里边进行维护。这样的话就能够避免数据库连接的频繁的创建和销毁&#xff0c;从而提高程序的效率。线程池其实也是同样的思路&#xf…

Mysql 编译安装部署

Mysql 编译安装部署 环境&#xff1a; 172.20.26.198&#xff08;Centos7.6&#xff09; 源码安装Mysql-5.7 大概步骤如下&#xff1a; 1、上传mysql-5.7.28.tar.gz 、boost_1_59_0.tar 到/usr/src 目录下 2、安装依赖 3、cmake 4、make && make install 5、…

【React】组件性能优化、高阶组件

文章目录 React性能优化SCUReact更新机制keys的优化render函数被调用shouldComponentUpdatePureComponentshallowEqual方法高阶组件memo 获取DOM方式refs如何使用refref的类型 受控和非受控组件认识受控组件非受控组件 React的高阶组件认识高阶函数高阶组件的定义应用一 – pro…

Ubuntu20.4 Mono C# gtk 编程习练笔记(三)

Mono对gtk做了很努力的封装&#xff0c;即便如此仍然与System.Windows.Form中的控件操作方法有许多差异&#xff0c;这是gtk本身特性或称为特色决定的。下面是gtk常用控件在Mono C#中的一些用法。 Button控件 在工具箱中该控件的clicked信号双击后自动生成回调函数prototype&…

spawn_group | spawn_group_template | linked_respawn

字段介绍 spawn_group | spawn_group_template 用来记录与脚本事件或boss战斗有关的 creatures | gameobjects 的刷新数据linked_respawn 用来将 creatures | gameobjects 和 boss 联系起来&#xff0c;这样如果你杀死boss&#xff0c; creatures | gameobjects 在副本重置之前…

华为OD机试 - 查找一个有向网络的头节点和尾节点(Java JS Python C)

题目描述 给定一个有向图,图中可能包含有环,图使用二维矩阵表示,每一行的第一列表示起始节点,第二列表示终止节点,如 [0, 1] 表示从 0 到 1 的路径。 每个节点用正整数表示。 求这个数据的首节点与尾节点,题目给的用例会是一个首节点,但可能存在多个尾节点。同时图中…

万户OA-senddocument_import.jsp任意文件上传

0x01阅读须知 本文章仅供参考&#xff0c;此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考。本文章仅用于信息安全防御技术分享&#xff0c;因用于其他用途而产生不良后果,作者不承担任何法律责任&#…

systemverilog/verilog文件操作

1、Verilog文件操作 Verilog具有系统任务和功能,可以打开文件、将值输出到文件、从文件中读取值并加载到其他变量和关闭文件。 1.1 、Verilog文件操作 1.1.1、打开和关闭文件 module tb; // 声明一个变量存储 file handler integer fd; initial begin // 以写权限打开一个文…

翻译: Anaconda 与 miniconda的区别

Anaconda 和 miniconda 是广泛用于数据科学的软件发行版&#xff0c;用于简化包管理和部署。 1. 主要有两个区别&#xff1a; packages包数量&#xff1a; Anaconda 附带了 150 多个数据科学包&#xff0c;而 miniconda 只有少数几个。Interface接口&#xff1a;Anaconda 有…

VC++中使用OpenCV进行颜色检测

VC中使用OpenCV进行颜色检测 在VC中使用OpenCV进行颜色检测非常简单&#xff0c;首选读取一张彩色图像&#xff0c;并调用函数cvtColor(img, imgHSV, COLOR_BGR2HSV);函数将原图img转换成HSV图像imgHSV&#xff0c;再设置好HSV三个分量的上限和下限值&#xff0c;调用inRange函…

android使用相机 intent.resolveActivity returns null

问题 笔者使用java进行android开发&#xff0c;启动相机时 intent.resolveActivity returns null takePictureIntent.resolveActivity(getPackageManager()) null详细问题 笔者使用如下代码启动相机 // 启动相机SuppressLint("LongLogTag")private void dispatc…

计算机网络——第四层:传输层以及TCP UDP

1. 传输层的协议 1.1 TCP (传输控制协议) - rfc793 连接模式的传输。 保证按顺序传送数据包。 流量控制、错误检测和在数据包丢失时的重传。 用于需要可靠传输的应用&#xff0c;如网络&#xff08;HTTP/HTTPS&#xff09;、电子邮件&#xff08;SMTP, IMAP, POP3&#xff09;…

TensorRT部署-Windows环境配置

系列文章目录 文章目录 系列文章目录前言一、安装Visual Studio &#xff08;2019&#xff09;二、下载和安装nvidia显卡驱动三、下载CUDA四、下载安装cuDNN五、安装Anaconda六、TensorRT安装七、安装Opencv八、Cmake 配置总结 前言 TensorRT部署-Windows环境配置 一、安装Vis…

微服务不死 — 共享变量在策略引擎项目的落地详解

01 背景 1、共享变量的提出 前段时间&#xff0c;来自亚马逊 Prime Video 团队的一个案例研究在开发者社区中掀起了轩然大波。大体是这样一件事&#xff0c;作为一个流媒体平台&#xff0c;Prime Video每天都会向客户提供成千上万的直播流。为了确保客户无缝接收内容&#xff0…

一、用户管理中心——前端初始化

一、Ant Design Pro初始化 1.创建空文件夹 2.打开Ant Design Pro官网 3.打开终端进行初始化 在终端输入npm i ant-design/pro-cli -g 在终端输入pro create myapp 选择umi3 选择simple 项目创建成功后&#xff0c;在文件夹中出现myapp 4.安装依赖 使用vscode打开项目 …