一文了解树在前端中的应用,掌握数据结构中树的生命线
一文了解樹在前端中的應(yīng)用
- 🏕?序言
- 🌲一、樹是什么?
- 🌴二、深/廣度優(yōu)先遍歷
- 1、深度優(yōu)先遍歷
- (1)定義
- (2)口訣
- (3)代碼實(shí)現(xiàn)
- 2、廣度優(yōu)先遍歷
- (1)定義
- (2)口訣
- (3)代碼實(shí)現(xiàn)
- 🌱三、二叉樹
- 1、定義
- 2、二叉樹的先/中/后序遍歷
- (1)先序遍歷
- (2)中序遍歷
- (3)后序遍歷
- 3、JS實(shí)現(xiàn)先中后序三種遍歷
- (1)JS實(shí)現(xiàn)二叉樹的先序遍歷
- (2)JS實(shí)現(xiàn)二叉樹的中序遍歷
- (3)JS實(shí)現(xiàn)二叉樹的后序遍歷
- (4)總結(jié)
- ??四、leetcode經(jīng)典題目剖析
- 1、leetcode104二叉樹的最大深度(簡單)
- 2、leetcode111二叉樹的最小深度(簡單)
- 3、leetcode102二叉樹的層序遍歷(中等)
- 4、leetcode94二叉樹的中序遍歷(簡單)
- 5、leetcode112路徑總和(簡單)
- 6、leetcode129求根節(jié)點(diǎn)到葉節(jié)點(diǎn)數(shù)字之和(中等)
- 🎄五、前端與樹:遍歷JSON的所有節(jié)點(diǎn)值
- 1、碎碎念
- 2、代碼實(shí)現(xiàn)
- (1)制造數(shù)據(jù)
- (2)遍歷節(jié)點(diǎn)值
- (3)打印結(jié)果
- 🏡六、結(jié)束語
- 🐣彩蛋One More Thing
- (:往期推薦
- (:番外篇
🏕?序言
在我們的日常生活中,無時(shí)無刻都會(huì)看到樹。比如,在街上行走時(shí),就有著一排排的樹。那么,樹在前端中,都有哪些應(yīng)用呢?
事實(shí)上,前端在寫頁面時(shí),每個(gè)頁面就有它對應(yīng)的 DOM 樹、 CSSOM 樹等等。除此之外呢,像我們寫級(jí)聯(lián)選擇器時(shí),它也是一層疊一層的,就像一棵樹一樣。
在接下來的這篇文章中,將講解樹這個(gè)數(shù)據(jù)結(jié)構(gòu)的一些基本操作,以及樹在前端中的應(yīng)用。
一起來學(xué)習(xí)叭~🧐
🌲一、樹是什么?
- 樹是一種具有分層數(shù)據(jù)功能的抽象模型。
- 前端工作中常用的樹包括: DOM 樹、級(jí)聯(lián)選擇、樹形空間……。
- JS 中沒有樹,但是可以用 Object 和 Array 構(gòu)建樹。
- 樹的常用操作:深度/廣度優(yōu)先遍歷、先中后序遍歷。
🌴二、深/廣度優(yōu)先遍歷
1、深度優(yōu)先遍歷
(1)定義
- 深度優(yōu)先遍歷,即盡可能深的搜索樹的分支。
(2)口訣
- 訪問根節(jié)點(diǎn)。
- 對根節(jié)點(diǎn)的 children 挨個(gè)進(jìn)行深度優(yōu)先遍歷。
(3)代碼實(shí)現(xiàn)
接下來用 JS 來實(shí)現(xiàn)樹的深度優(yōu)先遍歷。具體代碼如下:
const tree = {val:'a',children:[{val:'b',children:[{val:'d',children:[]},{val:'e',children:[]}]},{val:'c',children:[{val:'f',children:[]},{val:'a',children:[]}]}] }const dfs = (root) => {console.log(root.val);// 使用遞歸root.children.forEach(dfs); }/* 打印結(jié)果: a b d e c f a */通過以上代碼我們可以知道,首先我們先定義一棵樹 tree ,之后使用遞歸的方法,對樹的 Children 挨個(gè)進(jìn)行遍歷,最終得到 abdecfa 的打印結(jié)果。
這個(gè)順序怎么理解會(huì)更為容易一點(diǎn)呢?
在上面的知識(shí)點(diǎn)我們談到,樹是往深了遍歷。那在我們這道題的 tree 樹當(dāng)中,我們總得先對第一層的遍歷完,才能遍歷第二層的。而第一層的內(nèi)容又有很多層,那就先把它往深了遍歷,等到第一層的深度遍歷結(jié)束后,我們才開始遍歷第二層的。
所以,我們先在來看一下,最上面的是 a ,接著就是第一層,第一層有 bde ,接下來是第二層,第二層就有 cfa 。因此,最終的順序?yàn)?abdecfa 。
2、廣度優(yōu)先遍歷
(1)定義
- 廣度優(yōu)先遍歷,即先訪問根節(jié)點(diǎn)最近的節(jié)點(diǎn)。
(2)口訣
- 新建一個(gè)隊(duì)列。
- 把隊(duì)頭出隊(duì)并訪問。
- 把隊(duì)頭的 children 挨個(gè)入隊(duì)。
- 重復(fù)第二步和第三步,直到隊(duì)列為空。
(3)代碼實(shí)現(xiàn)
接下來用 JS 來實(shí)現(xiàn)樹的廣度優(yōu)先遍歷。具體代碼如下:
const tree = {val:'a',children:[{val:'b',children:[{val:'d',children:[]},{val:'e',children:[]}]},{val:'c',children:[{val:'f',children:[]},{val:'a',children:[]}]}] }const bfs = (root) => {// 新建一個(gè)隊(duì)列,并把根節(jié)點(diǎn)先放到隊(duì)列里面const q = [root];while(q.length > 0){// 不斷進(jìn)行出隊(duì),訪問const n = q.shift();// 邊出隊(duì)邊訪問console.log(n.val);// 把隊(duì)頭的children挨個(gè)入隊(duì),退到隊(duì)列里面n.children.forEach(child => {q.push(child);});} }bfs(tree);/* 打印結(jié)果: a b c d e f a */🌱三、二叉樹
1、定義
- 對于二叉樹來說,樹中的每個(gè)節(jié)點(diǎn)最多只能有兩個(gè)子節(jié)點(diǎn)。
- JS 中沒有二叉樹,但通常用對象 Object 模擬二叉樹。
2、二叉樹的先/中/后序遍歷
(1)先序遍歷
- 訪問根節(jié)點(diǎn)。
- 對根節(jié)點(diǎn)的左子樹進(jìn)行先序遍歷。
- 對根節(jié)點(diǎn)的右子樹進(jìn)行先序遍歷。
(2)中序遍歷
- 對根節(jié)點(diǎn)的左子樹進(jìn)行中序遍歷。
- 訪問根節(jié)點(diǎn)。
- 對根節(jié)點(diǎn)的右子樹進(jìn)行中序遍歷。
(3)后序遍歷
-
對根節(jié)點(diǎn)的左子樹進(jìn)行后序遍歷。
-
對根節(jié)點(diǎn)的右子樹進(jìn)行后序遍歷。
-
訪問根節(jié)點(diǎn)。
3、JS實(shí)現(xiàn)先中后序三種遍歷
下面我們用代碼來實(shí)現(xiàn)二叉樹的這三種遍歷。接下來開始講解~
(1)JS實(shí)現(xiàn)二叉樹的先序遍歷
對于二叉樹的先序遍歷來說,是先訪問根節(jié)點(diǎn),之后再訪問左子樹,最后訪問右子樹。下面我們用兩種方式來實(shí)現(xiàn)先序遍歷,第一種是遞歸版本,第二種是非遞歸版本。
先定義一棵樹:
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}} }遞歸版本實(shí)現(xiàn):
// 遞歸版本實(shí)現(xiàn) const preOrder1 = (root) => {if(!root){return;}console.log(root.val);preOrder1(root.left);preOrder1(root.right); }preOrder1(bt); /**打印結(jié)果: 1 2 4 5 3 6 7 */非遞歸版本實(shí)現(xiàn):
// 非遞歸版實(shí)現(xiàn) /*** 思路:* 1.新建一個(gè)棧模擬函數(shù)的調(diào)用堆棧;* 2.對于先序遍歷來說,需要先把根節(jié)點(diǎn)取出,然后再遍歷左子樹了右子樹;* 3.按照棧的先進(jìn)后出特點(diǎn),先把右子樹放進(jìn)棧里,再把左子樹放進(jìn)棧里,一一取出。*/ const preOrder2 = (root) => {if(!root){return;}// 新建一個(gè)stack代表函數(shù)的調(diào)用堆棧const stack = [root];// console.log(stack)while(stack.length){// 將根節(jié)點(diǎn)從棧里彈出const n = stack.pop();console.log(n.val);if(n.right){stack.push(n.right);}if(n.left){stack.push(n.left);}} }preOrder2(bt); /**打印結(jié)果: 1 2 4 5 3 6 7 */(2)JS實(shí)現(xiàn)二叉樹的中序遍歷
對于二叉樹的中序遍歷來說,是先訪問左子樹,之后訪問根節(jié)點(diǎn),最后再訪問右子樹。下面我們用兩種方式來實(shí)現(xiàn)中序遍歷,第一種是遞歸版本,第二種是非遞歸版本。
同樣地,我們先來先定義一棵樹:
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}} }遞歸版本實(shí)現(xiàn):
// 遞歸版本實(shí)現(xiàn) const inOrder1 = (root) => {if(!root){return;}inOrder(root.left);console.log(root.val);inOrder(root.right); }inOrder1(bt); /**打印結(jié)果: 4 2 5 1 6 3 7 */非遞歸版本實(shí)現(xiàn):
// 非遞歸版實(shí)現(xiàn) /*** 思路:* 1.新建一個(gè)棧模擬函數(shù)的調(diào)用堆棧;* 2.對于中序遍歷來說,需要先把左子樹全部丟到棧里面;那么需要每當(dāng)遍歷一個(gè),就推到棧里面* 3.遍歷完成之后,把最盡頭的結(jié)點(diǎn)彈出,并訪問它;此處最盡頭的結(jié)點(diǎn)即盡頭出的根節(jié)點(diǎn),左根右* 4.訪問完左結(jié)點(diǎn)后,需要訪問右結(jié)點(diǎn);*/ const inOrder2 = (root) => {if(!root){return;}let p = root;const stack = [];while(p || stack.length){while(p){// 先進(jìn)棧stack.push(p);// 進(jìn)棧完繼續(xù)指向左子樹p = p.left;}// 彈出最后一個(gè)const n = stack.pop();console.log(n.val);p = n.right;}}inOrder2(bt); /**打印結(jié)果: 4 2 5 1 6 3 7 */(3)JS實(shí)現(xiàn)二叉樹的后序遍歷
對于二叉樹的后序遍歷來說,是先訪問左子樹,之后訪問右子樹,最后再訪問根節(jié)點(diǎn)。下面我們用兩種方式來實(shí)現(xiàn)后序遍歷,第一種是遞歸版本,第二種是非遞歸版本。
首先同樣地,先來定義一棵樹:
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}} }遞歸版本實(shí)現(xiàn):
// 遞歸版本實(shí)現(xiàn) const postOrder1 = (root) => {if(!root){return;}postOrder1(root.left);postOrder1(root.right);console.log(root.val); }preOrder1(bt); /**打印結(jié)果: 1 2 4 5 3 6 7 */非遞歸版本實(shí)現(xiàn):
// 非遞歸版實(shí)現(xiàn) /*** 思路:* 1.建立一個(gè)空棧stack;* 2.分別把左子樹,右子樹分別放入stack棧* 3.建立一個(gè)倒序棧outputStack,先把根樹放進(jìn),再一一放入右子樹,右子樹全部放完之后再放左子樹*/ 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); /**打印結(jié)果: 1 2 4 5 3 6 7 */(4)總結(jié)
看完上面的代碼實(shí)現(xiàn)后,我們來做個(gè)總結(jié)。為什么這里要展示遞歸版本和非遞歸版本呢?
事實(shí)上,在我們的日常開發(fā)中,遞歸遍歷是非常常見的。但試想一下,有時(shí)候我們的業(yè)務(wù)邏輯有可能很復(fù)雜,那這個(gè)時(shí)候前端從后端接收到的數(shù)據(jù)量是比較大的。這個(gè)時(shí)候如果用遞歸版本來處理的話,算法復(fù)雜度相對來說就會(huì)比較高了。
所以我們多了一種非遞歸版本的實(shí)現(xiàn)方式,非遞歸版本的實(shí)現(xiàn)方式,旨在以空間來換時(shí)間,減少代碼的時(shí)間復(fù)雜度。
??四、leetcode經(jīng)典題目剖析
接下來我們引用幾道經(jīng)典的 leetcode 算法,來鞏固樹和二叉樹的知識(shí)。
1、leetcode104二叉樹的最大深度(簡單)
(1)題意
附上題目鏈接:leetcode104二叉樹的最大深度
給定一個(gè)二叉樹,找出其最大深度。
二叉樹的深度為根節(jié)點(diǎn)到最遠(yuǎn)葉子節(jié)點(diǎn)的最長路徑上的節(jié)點(diǎn)數(shù)。
說明: 葉子節(jié)點(diǎn)是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)。
輸入輸出示例:
- 輸入: 給定二叉樹 [3,9,20,null,null,15,7]
- 輸出: 3
(2)解題思路
- 求最大深度,考慮使用深度優(yōu)先遍歷。
- 在深度優(yōu)先遍歷過程中,記錄每個(gè)節(jié)點(diǎn)所在的層級(jí),找出最大的層級(jí)即可。
(3)解題步驟
- 新建一個(gè)變量,記錄最大深度。
- 深度優(yōu)先遍歷整棵樹,并記錄每個(gè)節(jié)點(diǎn)的層級(jí),同時(shí)不斷刷新最大深度的這個(gè)變量。
- 遍歷結(jié)束返回最大深度的變量。
(4)代碼實(shí)現(xiàn)
/*** @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二叉樹的最小深度
給定一個(gè)二叉樹,找出其最小深度。
最小深度是從根節(jié)點(diǎn)到最近葉子節(jié)點(diǎn)的最短路徑上的節(jié)點(diǎn)數(shù)量。
**說明:**葉子節(jié)點(diǎn)是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)。
輸入輸出示例:
- 輸入: root = [3,9,20,null,null,15,7]
- 輸出: 2
(2)解題思路
- 求最小深度,考慮使用廣度優(yōu)先遍歷。
- 在廣度優(yōu)先遍歷過程中,遇到葉子節(jié)點(diǎn),停止遍歷,返回節(jié)點(diǎn)層級(jí)。
(3)解題步驟
- 廣度優(yōu)先遍歷整棵樹,并記錄每個(gè)節(jié)點(diǎn)的層級(jí)。
- 遇到葉子節(jié)點(diǎn),返回節(jié)點(diǎn)層級(jí),停止遍歷。
(4)代碼實(shí)現(xiàn)
/*** @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二叉樹的層序遍歷
給你一個(gè)二叉樹,請你返回其按 層序遍歷 得到的節(jié)點(diǎn)值。 (即逐層地,從左到右訪問所有節(jié)點(diǎn))。
輸入輸出示例:
-
輸入: 二叉樹:[3,9,20,null,null,15,7]
3/ \9 20/ \15 7 -
輸出:
[[3],[9,20],[15,7] ]
(2)解題思路
- 層序遍歷順序就是廣度優(yōu)先遍歷。
- 不過在遍歷時(shí)候需要記錄當(dāng)前節(jié)點(diǎn)所處的層級(jí),方便將其添加到不同的數(shù)組中。
(3)解題步驟
- 廣度優(yōu)先遍歷二叉樹。
- 遍歷過程中,記錄每個(gè)節(jié)點(diǎn)的層級(jí),并將其添加到不同的數(shù)組中。
(4)代碼實(shí)現(xiàn)
/*** @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]){// 沒有該層次的數(shù)組時(shí)先創(chuàng)建一個(gè)數(shù)組res.push([n.val]);}else{// 有數(shù)組時(shí)直接將值放進(jìn)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二叉樹的中序遍歷
給定一個(gè)二叉樹的根節(jié)點(diǎn) root ,返回它的 中序 遍歷。
輸入輸出示例:
- 輸入: root = [1,null,2,3]
- 輸出: [1,3,2]
(2)解題思路&&解題步驟
- 這里的解題思路和步驟和上方講中序遍歷時(shí)類似,所以不再做講解,下面直接看代碼實(shí)現(xiàn)。
(3)代碼實(shí)現(xiàn)
/*** @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路徑總和
給你二叉樹的根節(jié)點(diǎn) root 和一個(gè)表示目標(biāo)和的整數(shù) targetSum ,判斷該樹中是否存在 根節(jié)點(diǎn)到葉子節(jié)點(diǎn) 的路徑,這條路徑上所有節(jié)點(diǎn)值相加等于目標(biāo)和 targetSum 。
葉子節(jié)點(diǎn) 是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)。
輸入輸出示例:
- 輸入: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
- 輸出: true
(2)解題思路
- 在深度優(yōu)先遍歷的過程中,記錄當(dāng)前路徑思維節(jié)點(diǎn)值的和。
- 在葉子節(jié)點(diǎn)處,判斷當(dāng)前路徑的節(jié)點(diǎn)值的和是否等于目標(biāo)值。
(3)解題步驟
- 深度優(yōu)先遍歷二叉樹,在葉子節(jié)點(diǎn)處,判斷當(dāng)前路徑路徑的節(jié)點(diǎn)值的和是否等于目標(biāo)值,是就返回true。
- 遍歷結(jié)束,如果沒有匹配,就返回false。
(4)代碼實(shí)現(xiàn)
/*** @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求根節(jié)點(diǎn)到葉節(jié)點(diǎn)數(shù)字之和(中等)
(1)題意
附上題目鏈接:leetcode129求根節(jié)點(diǎn)到葉節(jié)點(diǎn)數(shù)字之和
給你一個(gè)二叉樹的根節(jié)點(diǎn) root ,樹中每個(gè)節(jié)點(diǎn)都存放有一個(gè) 0 到 9 之間的數(shù)字。
每條從根節(jié)點(diǎn)到葉節(jié)點(diǎn)的路徑都代表一個(gè)數(shù)字:
例如,從根節(jié)點(diǎn)到葉節(jié)點(diǎn)的路徑 1 -> 2 -> 3 表示數(shù)字 123 。
計(jì)算從根節(jié)點(diǎn)到葉節(jié)點(diǎn)生成的 所有數(shù)字之和 。
葉節(jié)點(diǎn) 是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)。
輸入輸出示例:
- 輸入: root = [1,2,3]
- 輸出: 25
- 解釋:
- 從根到葉子節(jié)點(diǎn)路徑 1->2 代表數(shù)字 12
- 從根到葉子節(jié)點(diǎn)路徑 1->3 代表數(shù)字 13
- 因此,數(shù)字總和 = 12 + 13 = 25
(2)解題思路
- 在深度優(yōu)先遍歷的過程中,記錄當(dāng)前路徑前面節(jié)點(diǎn)的值。
- 在葉子節(jié)點(diǎn)處,計(jì)算出當(dāng)前路徑值。
(3)解題步驟
- 深度優(yōu)先遍歷二叉樹,直到每一棵樹的葉子節(jié)點(diǎn)處結(jié)束。
- 遍歷結(jié)束,返回所有路徑值。
(4)代碼實(shí)現(xiàn)
/*** @param {TreeNode} root* @return {number}*/var sumNumbers = function(root) {// 深度優(yōu)先遍歷處理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的所有節(jié)點(diǎn)值
1、碎碎念
有時(shí)候,后端傳過來的數(shù)據(jù)可能不是很友好,有可能一串?dāng)?shù)據(jù)里面又是對象又是數(shù)組的,這個(gè)時(shí)候前端拿到數(shù)據(jù)后,就需要稍微處理一下了。
因此,我們可以通過深度優(yōu)先遍歷來遍歷 JSON 中的所有節(jié)點(diǎn)值。
接下來用一個(gè)例子來展示~
2、代碼實(shí)現(xiàn)
(1)制造數(shù)據(jù)
假設(shè)我們心在有一串 json 的數(shù)據(jù),代碼如下:
const json = {a:{b:{c:1}},d:[1, 2] }(2)遍歷節(jié)點(diǎn)值
接下來,我們用深度優(yōu)先遍歷的方式,來遍歷 JSON 中的所有節(jié)點(diǎn)值。具體實(shí)現(xiàn)代碼如下:
const dfs = (n, path) => {console.log(n, path);Object.keys(n).forEach(k => {dfs(n[k], path.concat(k));}); };dfs(json, []);(3)打印結(jié)果
最終打印結(jié)果如下:
{ 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' ]大家看上面的打印結(jié)果可以發(fā)現(xiàn),通過深度優(yōu)先遍歷的方式,數(shù)據(jù)都被一一遍歷出來。因此,對于樹這種數(shù)據(jù)結(jié)構(gòu)來說,在前端當(dāng)中出現(xiàn)的頻率也是較高的~~
🏡六、結(jié)束語
通過上文的學(xué)習(xí),我們了解了樹的兩種遍歷:深度優(yōu)先遍歷和廣度優(yōu)先遍歷。同時(shí),還有一種特殊的樹,二叉樹。二叉樹在面試中,基本上是一大必考點(diǎn)。對于二叉樹來說,要了解它的三種遍歷方式:先序、中序和后序遍歷,并且要掌握好這三者之間的區(qū)別以及常見的應(yīng)用場景。
關(guān)于樹在前端中的應(yīng)用講到這里就結(jié)束啦!希望對大家有幫助~
如有疑問或文章有誤歡迎評(píng)論區(qū)留言或公眾號(hào)后臺(tái)加我微信提問~
🐣彩蛋One More Thing
(:往期推薦
棧👉棧在前端中的應(yīng)用,順便再了解下深拷貝和淺拷貝!
隊(duì)列👉詳解隊(duì)列在前端的應(yīng)用,深剖JS中的事件循環(huán)Eventloop,再了解微任務(wù)和宏任務(wù)
鏈表👉詳解鏈表在前端的應(yīng)用,順便再弄懂原型和原型鏈!
字典和集合👉ES6的Set和Map你都知道嗎?一文了解集合和字典在前端中的應(yīng)用
動(dòng)態(tài)規(guī)則和分而治之算法👉一文了解分而治之和動(dòng)態(tài)規(guī)則算法在前端中的應(yīng)用
貪心算法和回溯算法👉一文了解貪心算法和回溯算法在前端中的應(yīng)用
(:番外篇
- 關(guān)注公眾號(hào)星期一研究室,第一時(shí)間關(guān)注學(xué)習(xí)干貨,更多精選專欄待你解鎖~
- 如果這篇文章對你有用,記得留個(gè)腳印jio再走哦~
- 以上就是本文的全部內(nèi)容!我們下期見!👋👋👋
總結(jié)
以上是生活随笔為你收集整理的一文了解树在前端中的应用,掌握数据结构中树的生命线的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 甘草杏的功效与作用、禁忌和食用方法
- 下一篇: 米皮的功效与作用、禁忌和食用方法