一文了解树🌳在前端中的应用,掌握数据结构中树的生命线(二)

简介: 在接下来的这篇文章中,将讲解树这个数据结构的一些基本操作,以及树在前端中的应用。

☘️四、leetcode经典题目剖析


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


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


(1)题意

附上题目链接:leetcode104二叉树的最大深度

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

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

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

输入输出示例:

  • 输入: 给定二叉树 [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二叉树的最小深度

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

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

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

输入输出示例:

  • 输入: 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二叉树的层序遍历

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

输入输出示例:

  • 输入: 二叉树:[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二叉树的中序遍历

给定一个二叉树的根节点 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(p){
            stack.push(p);
            p = p.left;
        }
        const n = stack.pop();
        res.push(n.val);
        p = n.right;
    }
    return res;
}
inorderTraversal1(root);
inorderTraversal2(root);
复制代码


5、leetcode112路径总和(简单)


(1)题意

附上题目链接:leetcode112路径总和

给你二叉树的根节点 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求根节点到叶节点数字之和

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

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

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

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

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

输入输出示例:

  • 输入: root = [1,2,3]
  • 输出: 25
  • 解释:
  • 从根到叶子节点路径 1->2 代表数字 12
  • 从根到叶子节点路径 1->3 代表数字 13
  • 因此,数字总和 = 12 + 13 = 25

(2)解题思路

  • 在深度优先遍历的过程中,记录当前路径前面节点的值。
  • 在叶子节点处,计算出当前路径值。

(3)解题步骤

  • 深度优先遍历二叉树,直到每一棵树的叶子节点处结束。
  • 遍历结束,返回所有路径值。

(4)代码实现

/**
 * @param {TreeNode} root
 * @return {number}
 */
 var sumNumbers = function(root) {
    // 深度优先遍历处理
    const dfs = (n, preNum) => {
        if(!n){
            return 0;
        }
        const sum = preNum * 10 + n.val;
        if(!n.left && !n.right){
            return sum;
        }else{
            return dfs(n.left, sum) + dfs(n.right, sum);
        }
    }
    return dfs(root, 0);
};
复制代码


🎄五、前端与树:遍历JSON的所有节点值


1、碎碎念


有时候,后端传过来的数据可能不是很友好,有可能一串数据里面又是对象又是数组的,这个时候前端拿到数据后,就需要稍微处理一下了。

因此,我们可以通过深度优先遍历来遍历 JSON 中的所有节点值。

接下来用一个例子来展示~


2、代码实现


(1)制造数据

假设我们心在有一串 json 的数据,代码如下:

const json = {
    a:{
        b:{
            c:1
        }
    },
    d:[1, 2]
}
复制代码

(2)遍历节点值

接下来,我们用深度优先遍历的方式,来遍历 JSON 中的所有节点值。具体实现代码如下:

const dfs = (n, path) => {
    console.log(n, path);
    Object.keys(n).forEach(k => {
        dfs(n[k], path.concat(k));
    });
};
dfs(json, []);
复制代码

(3)打印结果

最终打印结果如下:

{ a: { b: { c: 1 } }, d: [ 1, 2 ] } []
{ b: { c: 1 } } [ 'a' ]
{ c: 1 } [ 'a', 'b' ]
1 [ 'a', 'b', 'c' ]
[ 1, 2 ] [ 'd' ]
1 [ 'd', '0' ]
2 [ 'd', '1' ]
复制代码

大家看上面的打印结果可以发现,通过深度优先遍历的方式,数据都被一一遍历出来。因此,对于树这种数据结构来说,在前端当中出现的频率也是较高的~~


🏡六、结束语


通过上文的学习,我们了解了树的两种遍历:深度优先遍历和广度优先遍历。同时,还有一种特殊的树,二叉树。二叉树在面试中,基本上是一大必考点。对于二叉树来说,要了解它的三种遍历方式:先序、中序和后序遍历,并且要掌握好这三者之间的区别以及常见的应用场景。

关于树在前端中的应用讲到这里就结束啦!希望对大家有帮助~



相关文章
|
16天前
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
53 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
16天前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
39 12
|
16天前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
39 10
|
16天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
39 2
|
2月前
|
JavaScript 前端开发 测试技术
构建高效可维护的前端应用
构建高效可维护的前端应用
|
1月前
|
移动开发 缓存 前端开发
深入理解前端路由:原理、实现与应用
本书《深入理解前端路由:原理、实现与应用》全面解析了前端路由的核心概念、工作原理及其实现方法,结合实际案例探讨了其在现代Web应用中的广泛应用,适合前端开发者和相关技术人员阅读。
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
91 5
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
84 1
|
2月前
|
自然语言处理 前端开发 JavaScript
深入理解前端中的 “this” 指针:从基础概念到复杂应用
本文全面解析前端开发中“this”指针的运用,从基本概念入手,逐步探讨其在不同场景下的表现与应用技巧,帮助开发者深入理解并灵活掌握“this”的使用。
|
2月前
|
存储 前端开发 JavaScript
前端中对象的深度应用与最佳实践
前端对象应用涉及在网页开发中使用JavaScript等技术创建和操作对象,以实现动态交互效果。通过定义属性和方法,对象可以封装数据和功能,提升代码的组织性和复用性,是现代Web开发的核心技术之一。