特点
一种分层数据的抽象模型
操作
- 深度优先遍历
- 广度优先遍历
- 二叉树的前/中/后序遍历
演示
// 深度优先遍历
// 尽可能深的搜索书的分支
// 访问根节点,然后对根节点的子节点挨个进行深度遍历(递归);
const dfs = (root) => {
console.log(root.val);
root.children.forEach(dfs);
};
// 广度优先遍历
// 新建一个队列,把根节点入队,
// 把对头出对并访问,把对头的children挨个入队;(重复操作,直到队列为空)
const bfs = (root) => {
const queue = [root];
while (queue.length > 0) {
const node = queue.shift();
console.log(node.val);
node.children.forEach((item) => {
queue.push(item);
});
}
};
二叉树的前/中/后序遍历
// 先序遍历(根左右)
// 操作:先访问根节点,对根节点的左子树先序遍历,对根节点的右子树先序便利;
const preorder = (root) => {
if (!root) return;
console.log(root.val);
preorder(root.left);
preorder(root.right);
};
//非递归版
const inorder = (root) => {
if (!root) return;
const stack = [root];
while (stack.length) {
const node = stack.pop();
console.log(node.val);
if (node.right) stack.push(node.right);
if (node.left) stack.push(node.left);
}
};
// 中序遍历(左根右)
// 操作:先访问根节点的左子树,进行中序便利,访问根节点,对根节点的右子树进行中序便利;
const inorder = root =>{
if (!root) return ;
inorder(root.left);
console.log(root.val);
inorder(root.right);
}
// 非递归版
const inorder = (root) => {
if (!root) return;
const stack = [];
let p = root;
while (stack.length || p) {
while (p) {
stack.push(p);
p = p.left;
}
const node = stack.pop();
console.log(node.val);
p = node.right;
}
};
// 后序遍历(左右根)
// 操作:对根节点的左子树后序遍历,对根节点的右子树后序遍历,访问根节点
const postorder = root =>{
if(!root) return ;
postorder(root.left);
postorder(root.right);
console.log(root.val);
}
//非递归版
const postorder = (root) => {
if (!root) return;
const stack = [root];
const outputStack = [];
while (stack.length) {
const node = stack.pop();
outputStack.push(node);
if (node.left) stack.push(node.left);
if (node.right) stack.push(node.right);
}
while (outputStack.length) {
const node = outputStack.pop();
console.log(node.val);
}
};
练习题
104. 二叉树的最大深度
// 求最大的深度,考虑使用深度优先遍历,深度优先遍历中,记录每个节点的层级,找出最大的层级
var maxDepth = function(root) {
let res = 0;
const dfs = (root,len) =>{
if (!root) return;
res = Math.max(len,res); // if (!root.left && !root.right) res = Math.max(len, res);
if (root.left) dfs(root.left,len+1);
if (root.right) dfs(root.right,len+1);
}
dfs(root,1);
return res;
};
111. 二叉树的最小深度
// 求最小的深度,优先考虑广度优先遍历;遇到叶子结点,停止遍历,返回节点层级;
var minDepth = function (root) {
if (!root) return 0;
const queue = [[root, 1]];
while (queue.length) {
const [node, len] = queue.shift();
if (!node.left && !node.right) return len;
if (node.left) queue.push([node.left, len + 1]);
if (node.right) queue.push([node.right, len + 1]);
}
};
102. 二叉树的层序遍历
var levelOrder = function (root) {
// 层序遍历就是广度优先遍历
// 遍历的时候记录当前节点所处的层级,将其节点按层级添加到数组中;
if (!root) return [];
const res = [];
const queue = [[root, 0]];
while (queue.length > 0) {
const [node, len] = queue.shift();
if (res[len]) { // 当前层级是否存在
res[len].push(node.val);
} else {
res[len] = [node.val];
}
if (node.left) queue.push([node.left, len + 1]);
if (node.right) queue.push([node.right, len + 1]);
}
return res;
};
var levelOrder = function(root) {
if(!root) return [];
const queue = [root];
const res = [];
while(queue.length){
let len = queue.length;
res.push([])
while(len--){
const node = queue.shift();
res[res.length-1].push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
}
return res;
};
112. 路径总和
// 深度优先遍历,记录当前路径节的节点值的和,判断当前节点是否和目标节点相当;
var hasPathSum = function (root, targetSum) {
let res = false;
if (!root) return res;
const dfs = (root, val) => {
if (!root) return;
if (!root.left && !root.right && val === targetSum) res = true;
if (root.left) dfs(root.left, root.val + val);
if (root.right) dfs(root.right, root.val + val);
};
dfs(root, root.val);
return res;
};