一文了解树在前端中的应用,掌握数据结构中树的生命线_先序遍历在实际生活中的应用(4)

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

        right:null
    }
},
right:{
    val:3,
    left:{
        val:6,
        left:null,
        right:null
    },
    right:{
        val:7,
        left:null,
        right:null
    }
}

}


**递归版本实现:**



// 递归版本实现
const preOrder1 = (root) => {
if(!root){
return;
}
console.log(root.val);
preOrder1(root.left);
preOrder1(root.right);
}

preOrder1(bt);
/**打印结果:
1
2
4
5
3
6
7
*/


**非递归版本实现:**



// 非递归版实现
/**
* 思路:
* 1.新建一个栈模拟函数的调用堆栈;
* 2.对于先序遍历来说,需要先把根节点取出,然后再遍历左子树了右子树;
* 3.按照栈的先进后出特点,先把右子树放进栈里,再把左子树放进栈里,一一取出。
*/
const preOrder2 = (root) => {
if(!root){
return;
}
// 新建一个stack代表函数的调用堆栈
const stack = [root];
// console.log(stack)
while(stack.length){
// 将根节点从栈里弹出
const n = stack.pop();
console.log(n.val);
if(n.right){
stack.push(n.right);
}
if(n.left){
stack.push(n.left);
}

}

}

preOrder2(bt);
/**打印结果:
1
2
4
5
3
6
7
*/


#### (2)JS实现二叉树的中序遍历


对于二叉树的中序遍历来说,是先访问**左**子树,之后访问**根**节点,最后再访问**右**子树。下面我们用两种方式来实现中序遍历,第一种是**递归版本**,第二种是**非递归版本**。


同样地,我们先来**先定义一棵树:**



const bt = {
val:1,
left:{
val:2,
left:{
val:4,
left:null,
right:null
},
right:{
val:5,
left:null,
right:null
}
},
right:{
val:3,
left:{
val:6,
left:null,
right:null
},
right:{
val:7,
left:null,
right:null
}
}
}


**递归版本实现:**



// 递归版本实现
const inOrder1 = (root) => {
if(!root){
return;
}
inOrder(root.left);
console.log(root.val);
inOrder(root.right);
}

inOrder1(bt);
/**打印结果:
4
2
5
1
6
3
7
*/


**非递归版本实现:**



// 非递归版实现
/**
* 思路:
* 1.新建一个栈模拟函数的调用堆栈;
* 2.对于中序遍历来说,需要先把左子树全部丢到栈里面;那么需要每当遍历一个,就推到栈里面
* 3.遍历完成之后,把最尽头的结点弹出,并访问它;此处最尽头的结点即尽头出的根节点,左根右
* 4.访问完左结点后,需要访问右结点;
*/
const inOrder2 = (root) => {
if(!root){
return;
}
let p = root;
const stack = [];
while(p || stack.length){
while§{
// 先进栈
stack.push§;
// 进栈完继续指向左子树
p = p.left;
}
// 弹出最后一个
const n = stack.pop();
console.log(n.val);
p = n.right;
}

}

inOrder2(bt);
/**打印结果:
4
2
5
1
6
3
7
*/


#### (3)JS实现二叉树的后序遍历


对于二叉树的后序遍历来说,是先访问**左**子树,之后访问**右**子树,最后再访问**根**节点。下面我们用两种方式来实现后序遍历,第一种是**递归版本**,第二种是**非递归版本**。


首先同样地,**先来定义一棵树:**



const bt = {
val:1,
left:{
val:2,
left:{
val:4,
left:null,
right:null
},
right:{
val:5,
left:null,
right:null
}
},
right:{
val:3,
left:{
val:6,
left:null,
right:null
},
right:{
val:7,
left:null,
right:null
}
}
}


**递归版本实现:**



// 递归版本实现
const postOrder1 = (root) => {
if(!root){
return;
}
postOrder1(root.left);
postOrder1(root.right);
console.log(root.val);
}

preOrder1(bt);
/**打印结果:
1
2
4
5
3
6
7
*/


**非递归版本实现:**



// 非递归版实现
/**
* 思路:
* 1.建立一个空栈stack;
* 2.分别把左子树,右子树分别放入stack栈
* 3.建立一个倒序栈outputStack,先把根树放进,再一一放入右子树,右子树全部放完之后再放左子树
*/
const postOrder2 = (root) => {
if(!root){
return;
}
// 倒序栈输出,放根右左的顺序,之后再一一取出
const outputStack = [];
// 先放左子树,再放右子树,方便后面取出
const stack = [root];
while(stack.length){
const n = stack.pop();
outputStack.push(n);
if(n.left){
stack.push(n.left);
}
if(n.right){
stack.push(n.right);
}
}
while(outputStack.length){
const n = outputStack.pop();
console.log(n.val);
}
}
preOrder2(bt);
/**打印结果:
1
2
4
5
3
6
7
*/


#### (4)总结


看完上面的代码实现后,我们来做个总结。**为什么这里要展示递归版本和非递归版本呢?**


事实上,在我们的日常开发中,递归遍历是非常常见的。但试想一下,有时候我们的业务逻辑有可能很复杂,那这个时候前端从后端接收到的数据量是比较大的。这个时候如果用递归版本来处理的话,算法复杂度相对来说就会比较高了。


所以我们多了一种非递归版本的实现方式,非递归版本的实现方式,旨在**以空间来换时间**,减少代码的时间复杂度。


## ☘️四、leetcode经典题目剖析


接下来我们引用几道经典的 `leetcode` 算法,来巩固树和二叉树的知识。


### 1、leetcode104二叉树的最大深度(简单)


**(1)题意**


附上题目链接:[leetcode104二叉树的最大深度](https://bbs.csdn.net/topics/618545628)


给定一个二叉树,找出其最大深度。


二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。


**说明:** 叶子节点是指没有子节点的节点。


**输入输出示例:**


* **输入**: 给定二叉树 `[3,9,20,null,null,15,7]`
* **输出**: 3


**(2)解题思路**


* 求最大深度,考虑使用深**度优先遍历**。
* 在深度优先遍历过程中,**记录每个节点所在的层级**,找出**最大的层级**即可。


**(3)解题步骤**


* 新建一个变量,记录最大深度。
* 深度优先遍历整棵树,并记录每个节点的层级,同时不断刷新最大深度的这个变量。
* 遍历结束返回最大深度的变量。


**(4)代码实现**



/**
* @param {TreeNode} root
* @return {number}
*/
let maxDepth = function(root) {
let res = 0;
const dfs = (n, l) => {
if(!n){
return;
}
if(!n.left && !n.right){
res = Math.max(res, l);
}
dfs(n.left, l + 1);
dfs(n.right, l + 1);
}
dfs(root, 1);
return res;
}


### 2、leetcode111二叉树的最小深度(简单)


**(1)题意**


附上题目链接:[leetcode111二叉树的最小深度](https://bbs.csdn.net/topics/618545628)


给定一个二叉树,找出其最小深度。


最小深度是从根节点到最近叶子节点的最短路径上的节点数量。


\*\*说明:\*\*叶子节点是指没有子节点的节点。


**输入输出示例:**


* **输入**: root = `[3,9,20,null,null,15,7]`
* **输出**: 2


**(2)解题思路**


* 求最小深度,考虑使用广度优先遍历。
* 在广度优先遍历过程中,遇到叶子节点,停止遍历,返回节点层级。


**(3)解题步骤**


* 广度优先遍历整棵树,并记录每个节点的层级。
* 遇到叶子节点,返回节点层级,停止遍历。


**(4)代码实现**



/**
* @param {TreeNode} root
* @return {number}
*/

let minDepth = function(root){
if(!root){
return 0;
}

const q = [[root, 1]];
while(q.length){
    const [n, l] = q.shift();

    if(!n.left && !n.right){
        return l;
    }
    
    if(n.left){
        q.push([n.left, l + 1]);
    }
    if(n.right){
        q.push([n.right, l + 1]);
    }
}

}


### 3、leetcode102二叉树的层序遍历(中等)


**(1)题意**


附上题目链接:[leetcode102二叉树的层序遍历](https://bbs.csdn.net/topics/618545628)


给你一个二叉树,请你返回其按 **层序遍历** 得到的节点值。 (即逐层地,从左到右访问所有节点)。


**输入输出示例:**


* **输入**: 二叉树:`[3,9,20,null,null,15,7]`

 
3

/
9 20
/
15 7

* **输出**:

 

[
[3],
[9,20],
[15,7]
]



**(2)解题思路**


* 层序遍历顺序就是广度优先遍历。
* 不过在遍历时候需要记录当前节点所处的层级,方便将其添加到不同的数组中。


**(3)解题步骤**


* 广度优先遍历二叉树。
* 遍历过程中,记录每个节点的层级,并将其添加到不同的数组中。


**(4)代码实现**



/**
* @param {TreeNode} root
* @return {number[][]}
*/
// 方法一
let levelOrder1 = function(root) {
if(!root){
return [];
}
const q = [[root, 0]];
const res = [];
while(q.length){
const [n, level] = q.shift();
if(!res[level]){
// 没有该层次的数组时先创建一个数组
res.push([n.val]);
}else{
// 有数组时直接将值放进
res[level].push(n.val);
}
if(n.left){
q.push([n.left, level + 1]);
}
if(n.right){
q.push([n.right, level + 1]);
}
}
return res;
};

// 方法二
let levelOrder2 = function(root){
if(!root){
return [];
}
const q = [root];
const res = [];
while(q.length){
let len = q.length;
res.push([]);
while(len–){
const n = q.shift();
res[res.length - 1].push(n.val);
if(n.left){
q.push(n.left);
}
if(n.right){
q.push(n.right);
}
}
}
return res;
}


### 4、leetcode94二叉树的中序遍历(简单)


**(1)题意**


附上题目链接:[leetcode94二叉树的中序遍历](https://bbs.csdn.net/topics/618545628)


给定一个二叉树的根节点 `root` ,返回它的 **中序** 遍历。


**输入输出示例:**


* **输入**: root = `[1,null,2,3]`
* **输出**: `[1,3,2]`


**(2)解题思路&&解题步骤**


* 这里的解题思路和步骤和上方讲中序遍历时类似,所以不再做讲解,下面直接看代码实现。


**(3)代码实现**



/**
* @param {TreeNode} root
* @return {number[]}
*/
// 遍历版本
let inorderTraversal1 = function(root) {
const res = [];
const rec = (n) => {
if(!n){
return;
}
rec(n.left);
rec(n.val);
rec(n.right);
}
rec(root);
return res;
};

// 迭代版本——栈方法
let inorderTraversal2 = function(root){
const res = [];
const stack = [];
let p = root;
while(stack.length || p){
while§{
stack.push§;
p = p.left;
}
const n = stack.pop();
res.push(n.val);
p = n.right;
}
return res;
}

inorderTraversal1(root);
inorderTraversal2(root);


### 5、leetcode112路径总和(简单)


**(1)题意**


附上题目链接:[leetcode112路径总和](https://bbs.csdn.net/topics/618545628)


给你二叉树的根节点 `root` 和一个表示目标和的整数 `targetSum` ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 `targetSum` 。


**叶子节点** 是指没有子节点的节点。


**输入输出示例:**


* **输入**: `root` = [5,4,8,11,null,13,4,7,2,null,null,null,1], `targetSum` = 22
* **输出**: true


**(2)解题思路**


* 在深度优先遍历的过程中,记录当前路径思维节点值的和。
* 在叶子节点处,判断当前路径的节点值的和是否等于目标值。


**(3)解题步骤**


* 深度优先遍历二叉树,在叶子节点处,判断当前路径路径的节点值的和是否等于目标值,是就返回true。
* 遍历结束,如果没有匹配,就返回false。


**(4)代码实现**



/**
* @param {TreeNode} root
* @param {number} targetSum
* @return {boolean}
*/
// 递归法
let hasPathSum = function(root, targetSum) {
if(!root){
return false;
}

let res = false;

const dfs = (n, s) => {
    if(!n.left && !n.right && s === targetSum){
        res = true;
    }
    if(n.left){
        dfs(n.left, s + n.left.val);
    }
    if(n.right){
        dfs(n.right, s + n.right.val);
    }
}
dfs(root, root.val);
return res;

};


### 6、leetcode129求根节点到叶节点数字之和(中等)


**(1)题意**


附上题目链接:[leetcode129求根节点到叶节点数字之和](https://bbs.csdn.net/topics/618545628)


给你一个二叉树的根节点 `root` ,树中每个节点都存放有一个 `0` 到 `9` 之间的数字。


每条从根节点到叶节点的路径都代表一个数字:


例如,从根节点到叶节点的路径 `1 -> 2 -> 3` 表示数字 `123` 。


计算从根节点到叶节点生成的 **所有数字之和** 。


**叶节点** 是指没有子节点的节点。



![img](https://img-blog.csdnimg.cn/img_convert/149ce33e9a67ec66685ffef2c831098b.png)
![img](https://img-blog.csdnimg.cn/img_convert/cf2c399d20b0130a3644a4fae4679b3b.png)
![img](https://img-blog.csdnimg.cn/img_convert/1fac564c53f93a7cbd4c54f402013891.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

  if(n.right){
            dfs(n.right, s + n.right.val);
        }
    }
    dfs(root, root.val);
    return res;
};

6、leetcode129求根节点到叶节点数字之和(中等)

(1)题意

附上题目链接:leetcode129求根节点到叶节点数字之和

给你一个二叉树的根节点 root ,树中每个节点都存放有一个 09 之间的数字。

每条从根节点到叶节点的路径都代表一个数字:

例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123

计算从根节点到叶节点生成的 所有数字之和

叶节点 是指没有子节点的节点。

[外链图片转存中…(img-3mRmGVro-1715721973299)]
[外链图片转存中…(img-3OlzOQw8-1715721973300)]
[外链图片转存中…(img-iAPm7HDp-1715721973300)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

  • 15
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值