树是什么?
在生活中 ‘树’ 肯定不陌生,随处可见,桃树、梨树、杨树、柳树·····
在计算机科学里面树是👇
- 一种分层数据的抽象模型
- 前端工作中常见的树有:DOM 树、级联选择、树形控件·····
- Js 中没有树,但是我们可以通过 Object 和 Array 构建树
- 树的常用操作:深度/广度优先遍历,先中后序遍历
深度/广度优先遍历
深度优先遍历:尽可能深的搜索树的分支
-
算法口诀:
- 访问根节点
- 对根节点的 children 挨个进行深度优先遍历
广度优先遍历:先访问离根节点进的节点
-
算法口诀:
- 新建一个队列,让根节点入队
- 把对头出队访问
- 把对头的children挨个入队
- 重复二、三,直至队列为空
const tree = {
val: 'a',
children:[
{
val: 'b',
children:[ { val: 'd' }, { val: 'e' } ]
},{
val: 'c',
children:[ { val: 'f' }, { val: 'g' } ]
},
]
}
// 深度优先遍历 coding
const depth = (root) => {
console.log(root.val,'Depth'); // a, b, d, e, c, f, g
root.children.forEach(depth);
}
depth(tree);
// 广度优先遍历 coding
const readth = (root) => {
const q = [root];
while (q.length) {
const n = q.shift();
console.log(n.val, 'readth'); // a, b, c, d, e, f, g
n.children.forEach(child => {
q.push(child);
})
}
}
readth(tree);
二叉树中的先中后序优先遍历
二叉树是?
- 树中的每个节点最多只能有两个子节点
- 在JavaScript中通常使用 Object 来模拟二叉树
先序遍历
- 访问
根节点 - 对根节点的
左子树进行先序遍历 - 对根节点的
右子树进行先序遍历
中序遍历
- 对根节点的
左子树进行中序遍历 - 访问 根 节点
- 对根节点的
右子树进行中序遍历
后序遍历
- 对根节点的
左子树进行中序遍历 - 对根节点的
右子树进行中序遍历 - 访问
根节点
const binaryTree = {
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 }
},
};
///////////// 先序遍历
// 1. 递归方法
function preorder1 (root) {
if (!root) return;
console.log(root.val) // 1,2,4,5,3,6,7
preorder(root.left);
preorder(root.right);
}
preorder1(binaryTree);
// 2. 非递归方法
function preorder2 (root) {
if (!root) return;
const stack = [root];
while (stack.length) {
const n = stack.pop();
console.log(n.val) // 1,2,4,5,3,6,7
if (n.right) stack.push(n.right);
if (n.left) stack.push(n.left)
}
}
preorder2(binaryTree);
//////////// 中序遍历
// 1. 递归方法
function inorder1 (root) {
if (!root) return;
inorder(root.left);
console.log(root.val) // 4, 2, 5, 1, 6, 3, 7
inorder(root.right);
}
inorder1(binaryTree);
// 2. 非递归方法
function inorder2 (root) {
if (!root) return;
const stack = [];
let p = root;
while (stack.length || p) {
while (p) {
stack.push(p);
p = p.left;
}
const n = stack.pop();
console.log(n.val) // 4, 2, 5, 1, 6, 3, 7
p = n.right;
}
}
inorder2(binaryTree);
//////////// 后序遍历
// 1. 递归方法
function endorder1 (root) {
if (!root) return;
inorder(root.left);
inorder(root.right);
console.log(root.val) // 4, 5, 2, 6, 7, 3, 1
}
endorder1(binaryTree);
// 2. 非递归方法
function endorder2 (root) {
if (!root) return;
const stack = [root];
const outputStack = [];
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) // 4, 5, 2, 6, 7, 3, 1
}
}
endorder2(binaryTree);
力扣 104-二叉树的最大深度
题目 : 给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
步骤:
- 给定一个变量,记录最大深度;
- 深度优先遍历整棵树,并记录每个节点的层级,同时不断刷新最大深度这个变量
- 遍历结束后,返回最大深度这个变量
// 使用了 深度优先遍历 方法
var maxDepth = function(root) {
let res = 0;
const dsf = (n, l) => {
if(!n) return;
if(!n.left && !n.right) {
res = Math.max(res, l);
}
dsf(n.left, l + 1);
dsf(n.right, l +1);
};
dsf(root, 1);
return res;
};