前言
今年相信很多小伙伴在面试过程中都遇到或多或少的算法题,既上一篇js算法之二分查找之后再推出一篇文章,二叉树的遍历。这两类型的题在面试中都很常见的,很多小伙伴不明白为什么前端也要考察二叉树,在阅读源码过程中有没有发现一些代码根本看不懂,比如vue,react中的DOM diff算法,为什么要涉及到树,堆,栈,链表,哈希表...如果你没有相关算法与数据结构经验的话阅读起来是相当困难的。
1、二叉树遍历
二叉树遍历又分为广度优先和深度优先,我们常说的中序、前序、后序一般指深度优先遍历。深度优先搜索(Depth First Search)是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。广度优先搜索(Breadth First Search),又叫宽度优先搜索或横向优先搜索,是从根结点开始沿着树的宽度搜索遍历。
2、深度优先之前、中、后序遍历

2.1、递归思想
/**
* @param {TreeNode} root
* @return {number[]}
*/
var inorderTraversal = function(root) {
const res = [];
const helper = node => {
if (!node) return;
// 前、中、后序遍历的区别就在以下三行
// 1、前序:根-->左-->右
res.push(node.val);
helper(node.left);
helper(node.right);
// 2、中序:左-->根-->右
helper(node.left);
res.push(node.val);
helper(node.right);
// 3、后序:右-->根-->左
helper(node.right);
res.push(node.val);
helper(node.left);
}
helper(root);
return res;
};
ES6的简单写法,以中序为例:
/**
* @param {TreeNode} root
* @return {number[]}
*/
var inorderTraversal = function(root) {
return root ? [...inorderTraversal(root.left), root.val, ...inorderTraversal(root.right)] : [];
};
2.2 迭代思想
以下是leetcode原题地址:
144.二叉树的前序遍历
94.二叉树的中序遍历
145.二叉树的后序遍历
思路:模拟栈,先进后出。由上面三序定义图解可以,对于二叉树任何一个节点而言,我们对它只有两种操作,一是将它作为根节点,在三序相应的遍历顺序中,取出其中的值作为结果集的一部分,二是继续探索它的左、右子树,按照三序的定义顺序来操作。所以我们可以在遍历过程中对任意一个节点附加一个标识,true:表示当前节点是三序遍历中相应顺序的根节点,碰到需要加入结果集,false:表示此节点属于三序遍历中的左、右子树的操作,需要压入栈中。
/**
* @param {TreeNode} root
* @return {number[]}
*/
var postorderTraversal = function(root) {
let res = [];
if (!root) return res;
let stack = [[root, false]];
while(stack.length > 0) {
const node = stack.pop();
let curr = node[0];
let isTrue = node[1];
if (isTrue) {
res.push(curr.val);
} else {
// 前、中、后序区别还是在以下代码,这个顺序要和上面的递归顺序相反
// 前:右--->左--->根
// 中:右--->根--->左
// 后:根--> 右--->左
if(curr.right){
stack.push([curr.right,false]);
}
if(curr.left){
stack.push([curr.left,false]);
}
stack.push([curr,true]);
}
}
return res;
};

3、广度优先之二叉树层序遍历
102.二叉树的层序遍历
广度优先使用队列思想处理,1、将一层记录在数组中 并记录数组长度2、找下一行所有数据3、将数组首位弹出 将首位的左右节点追在数组后4、按照记录的数组长度 将上层的结点全部弹出后 此时数组只剩下下一行结点了 此时就完成了一层的遍历。同样,还是有迭代和递归两种办法:
递归
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
var res = [];
if (!root) return res;
helper(root, 0, res);
return res;
};
function helper(root, level, res) {
if (res.length === level) {
res[level] = [];
}
res[level].push(root.val);
if (root.left) helper(root.left, level + 1, res);
if (root.right) helper(root.right, level + 1, res);
}
迭代
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
if(!root) return[];
let res = [], queue = [root]
while(queue.length) {
let arr =[], temp = [];
while(queue.length) {
let curr = queue.shift();
arr.push(curr.val);
if (curr.left) temp.push(curr.left);
if (curr.right) temp.push(curr.right);
}
queue = temp;
res.push(arr)
}
return res;
};
ennn,到此就告一段落了,当然二叉树的遍历还有很多方法,但是最常用的就是以上几种,主要考查的是递归、栈、队列的思想,熟练掌握会发现有很多题都可以用这三种方法来解。好了,小伙伴们练起来吧,多练习,祝各位看官早日diaoda面试官~