大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。
题目
144. 二叉树的前序遍历
给你二叉树的根节点 root
,返回它节点值的 前序 **遍历。
示例 1:
输入: root = [1,null,2,3]
输出: [1,2,3]
示例 2:
输入: root = []
输出: []
示例 3:
输入: root = [1]
输出: [1]
示例 4:
输入: root = [1,2]
输出: [1,2]
示例 5:
输入: root = [1,null,2]
输出: [1,2]
提示:
- 树中节点数目在范围
[0, 100]
内 -100 <= Node.val <= 100
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
思路
- 关于二叉树的前中后序遍历,如果还不了解的小伙伴们可以先看看我这篇文章,[路飞]_一文彻底搞懂二叉树的前序、中序、后序遍历;
- 递归的算法我们之前已经讲过了,这里不再多讲,今天主要跟大家分享一下如何通过迭代算法来实现;
- 其实有个特别简单的方法,我们可以用一个栈
nodeArr
来存储。从上到下,如果有左节点,我们就缓存下来,待会儿再挨个取出它们的右子节点,因为前序遍历是先遍历所有的左节点,再到右节点,所以我们每一轮拿出最下面的一个左节点,判断它是否存在左子节点,如果存在继续判断下一轮,同时拆断cur.left
的关系,不然下一轮取出来的时候会陷入死循环; - 如果最下面的左节点,不存在左子节点了,这时候我们需要输出右子节点,先序遍历中输出右子节点的顺序是自下向上的,这也是我们用栈的目的。每次我们取出最后一个,如果有右子节点再把右子节点塞回去给下一轮判断有没有左右子节点。每次必然是先判断左子节点,再判断右子节点,这样子当栈的长度为空时说明遍历结束。
实现
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
if (!root) return [];
let nodeArr = [ root ];
let result = [ root.val ];
// 当栈不为空一直运行
while (nodeArr.length) {
let cur = nodeArr[nodeArr.length - 1];
// 如果有左子节点, 存起来,待会儿从下往上一个个存右子节点
// 记得把cur.left的联系切断,不然下一轮进来就死循环了
if (cur.left) {
result.push(cur.left.val);
nodeArr.push(cur.left);
cur.left = null;
} else {
// 没有左子节点了,拿出最后一个,看看有没有右子节点
let last = nodeArr.pop();
// 如果有右子节点,拿它做下一轮的判断
if (last.right) {
result.push(last.right.val);
nodeArr.push(last.right);
cur.right = null;
}
}
}
return result;
};
总结
遇到二叉树的题目,一般用递归写法,但是如果想用迭代,基本都是用栈或者数组进行存储。这是因为栈的特性: 先进后出,这样子有利于我们从下往上去输出我们想要的值。
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。