【算法之LeetCode系列(7)】—— 二叉树的遍历

本文详细介绍了二叉树的四种遍历方法:前序遍历、中序遍历、后序遍历和层序遍历,并提供了JavaScript实现。前三种遍历主要通过递归完成,而层序遍历则利用队列实现。此外,还讨论了层序遍历的两种变式,包括常规层序遍历和锯齿形层序遍历。文章通过代码注释和图解帮助理解遍历过程。
摘要由CSDN通过智能技术生成

1.二叉树的前序遍历(easy)

前序遍历就是头结点永远第一访问,接着是头结点的左孩子节点,右孩子节点;后序遍历就是左、右、头结点;中序遍历就是左、头结点、右;

所以只要一道题你搞懂了,三道题就是一道题

//这里是官方给出的js中二叉树的构造函数(只写一遍哈)
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
var preorderTraversal = function(root) {
    let res = [];
    let helper = function(root){
        if(root === null) return;//如果是叶子节点,直接返回
        res.push(root.val);//1.将根节点压入
        helper(root.left);//2.递归遍历左子树,目的——>压入根节点的左子树的头结点
        helper(root.right);//3.递归遍历右子树,目的——>压入根节点的右子树的头结点
    }
    helper(root);
    return res;
};
2.二叉树的中序遍历(easy)
var preorderTraversal = function(root) {
    let res = [];
    let helper = function(root){
        if(root === null) return;//如果是叶子节点,直接返回
        helper(root.left);//1.递归遍历左子树
        res.push(root.val);//2.将根节点压入
        helper(root.right);//3.递归遍历右子树
    }
    helper(root);
    return res;
};
3.二叉树的后序遍历(easy)
var preorderTraversal = function(root) {
    let res = [];
    let helper = function(root){
        if(root === null) return;//如果是叶子节点,直接返回
        helper(root.left);//1.递归遍历左子树
        helper(root.right);//2.递归遍历右子树
        res.push(root.val);//3.将根节点压入
    }
    helper(root);
    return res;
};
4.二叉树的层序遍历(medium)

先给一下力扣官方的题目描述吧 ↓↓↓↓↓
在这里插入图片描述

层序遍历就是按照二叉树的结构,先遍历第一层(根节点)再遍历第二层,接着第三层……(还是看图吧,亲自手绘)

以下是我的图解
在这里插入图片描述

即结果输出要求,首先是第一层从左到右的节点,接着是第二层,第三层……,那这样改怎么做呢,显然,你用之前的递归是无法完成的,因为你递归是向深处遍历,纵向延伸,无法横向移动!

我们需要借助一个数据结构,队列,队列是先进先出表,你想啊,你每次遍历,先把节点压入队列中,只要队列中有东西,你就先遍历队列里面的,没有了我再接着遍历后面的,把后面一层的压入队列里面去,一直循环到没有节点为之,看代码上的详细注释

1. 层序遍历 I
var levelOrder = function(root) {
    let res= [];
    //定义一个队列,根据层次顺序保存节点
    let queue = [root];
    if(root === null) return res;
    while(queue.length > 0){
    	//每次从队列中弹出一个节点,并放到res中去
        let node = queue.shift();
        res.push(node.val);
        //检查弹出的节点,有没有子孩子,有就加入到队列中,这样就把下一层的节点顺序也安排的明明白白的
        if(node.left !== null) queue.push(node.left);
        if(node.right !== null) queue.push(node.right);
    }
    return res;
};

看完注释,如果还是不懂,来看看我的图趴

在这里插入图片描述

2. 层序遍历 I I(easy)(搞不懂为什么这个是easy,是因为变式I做出来了吗)

看一下官方题目描述 ↓↓↓↓↓

在这里插入图片描述

var levelOrder = function(root) {
    let res = [];//存放最终的遍历结果
    //定义一个队列,js中可以使用数组(shift和push方法)模仿一个队列
    let queue = [];
    //首先第一层,先把根节点放入队列,注意,这时候队列里面已经有东西了
    if(root !== null) queue.push(root);
   	//遍历队列里面的节点
    while(queue.length > 0){//只要队列的长度大于0,就一直循环遍历
    //注意,这里需要定义这个队列的长度n,不然队列的长度就是动态变化了哦
        let n = queue.length;
        //定义层级,即level是保存每一层的节点
        let level = [];
        //n是当前层的最大节点数量
        for(let i = 0;i < n;i ++){
        	//从队列头中取出一个节点
            let node = queue.shift();
            //将取出的节点的值压入当前层level
            level.push(node.val);
            //看看取出的这个节点有没有左右子孩子,有就压入到队列里面去
            //所以上面必须有一个n,每一层数量应该是确定好的,而下一层的节点数量也会在这一层遍历完之后确定好
            if(node.left) queue.push(node.left);
            if(node.right) queue.push(node.right);
        }
        //将当前层的节点作为一个整体压入结果中
        res.push(level);
    }
    return res;
};
3. 层序遍历 I I I(锯齿形层序遍历)

官方题目描述 ↓↓↓↓↓

在这里插入图片描述

其实变式三,就是变式二的一点小改动,每次压入当前层节点的位置不一样而已,奇数从队列的尾插入,偶数从队列头插入,而队列是在头部先进先出(一般),所以,每次出队列的顺序就会按奇偶而不同了

var levelOrder = function(root) {
    let count = 0;
    let ans = [];
    let res = [];
    let queue = [root];
    if(root ===  null) return res;
    while(queue.length > 0){
        count ++;//控制层数,遍历完一层,层数加一
        level = [];
        let len = queue.length;
        for(let i = 0;i < len;i ++){
            let node = queue.shift();
            //偶数层,从头部依次加入队列,这样,出队列就是最后一个进的先出队列
            //牢记unshift()方法是从数组第一个元素之前开始添加元素,即新添加的元素是数组的第一个元素
            if(count % 2 === 0) level.unshift(node.val);
            //奇数层,从队列尾部压入,这样,出队列就是正常顺序,从左向右
            else level.push(node.val);
            if(node.left !== null) queue.push(node.left);
            if(node.right !== null) queue.push(node.right);
        }
        res.push(level);
    }
    return res;
};

ok,今天就到这里了,感谢浏览,码字不易,不介意的话,给个一键三连再走呗 ヾ(◍°∇°◍)ノ゙

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

summer·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值