前序遍历
递归
var preorderTraversal = function(root) {
const res = [];
// 递归函数
function _preorder(node) {
if (!node) return;
res.push(node.val);
_preorder(node.left);
_preorder(node.right);
}
_preorder(root);
return res;
};
迭代
通过栈数据结构(先进后出),我们可以将父节点压入栈,对栈执行出栈操作,每次将出栈的节点的右孩子先压入栈,其次压入左孩子。这样就可以做到先遍历父节点,在遍历左孩子部分,后遍历右孩子部分。
var preorderTraversal = function(root) {
if (!root) return [];
const stack = [root];
const res = [];
while(stack.length) {
// 出栈
const cur = stack.pop();
res.push(cur.val);
// 子节点存在压入栈中,先右再左
cur.right && stack.push(cur.right);
cur.left && stack.push(cur.left);
}
return res;
};
中序遍历
递归
var inorderTraversal = function(root) {
const res = [];
// 递归函数
function _inorder(node) {
if (!node) return;
_inorder(node.left);
res.push(node.val);
_inorder(node.right);
}
_inorder(root);
return res;
};
迭代
我们同样可以使用栈结构来实现中序遍历,因为中序遍历左子树是优先遍历,所以父节点要先于子树的节点优先压入栈中,每当我们压入节点时,都要把节点的左子树的所有左节点压入栈中。
var inorderTraversal = function(root) {
if (!root) return [];
const stack = [];
let cur = root;
const res = [];
while (stack.length || cur) {
// 左节点都先压入栈
while (cur) {
stack.push(cur);
cur = cur.left;
}
const node = stack.pop();
res.push(node.val);
if (node.right != null) {
cur = node.right;
}
}
return res;
};
后序遍历
递归
var postorderTraversal = function(root) {
const res = [];
// 递归函数
function _postorder(node) {
if (!node) return;
_postorder(node.left);
_postorder(node.right);
res.push(node.val);
}
_postorder(root);
return res;
};
迭代
后序遍历是父节点需要最后被遍历。但其实可以跟前序遍历的实现方式上差不多,只不过在插入数组中,我们总是在头部插入,这样先被插入的节点值一定是相对于左右孩子后面的。
var postorderTraversal = function(root) {
if (!root) return null;
const res = [];
const stack = [root];
while (stack.length) {
const cur = stack.pop();
// 总是头部插入,先被插入的在后面。
res.unshift(cur.val);
cur.left && stack.push(cur.left);
cur.right && stack.push(cur.right);
}
return res;
};
层序遍历
递归
var levelOrder = function(root) {
const res = [];
function _levelOrder(node, level) {
if (!node) return null;
// 当前层数组初始化
res[level] = res[level] || [];
res[level].push(node.val);
// 下一层 +1
_levelOrder(node.left, level + 1);
_levelOrder(node.right, level + 1);
}
_levelOrder(root, 0);
return res;
};
迭代
我们使用队列来保存节点,每轮循环中,我们都取一层出来,将它们的左右孩子放入队列。
var levelOrder = function(root) {
if (root == null) return [];
const ans = [];
let level = 0;
const queue = [root];
while(queue.length) {
ans.push([]);
const len = queue.length;
// 通过遍历,提前执行完一层的所有元素,层级level就可以+1
for (let i = 0; i < len; i++) {
const node = queue.shift();
ans[level].push(node.val);
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
level++;
}
return ans;
};
总结
关于二叉树的前序、中序、后续遍历,使用递归的方法不用多说,主要是迭代方法,通过对栈
的应用,对节点不同顺序的压入栈中,从而实现不同顺序的遍历。二叉树的层序遍历迭代方式则是通过对队列
的应用。