递归的三要素:
- 递归函数的参数和返回值
- 单层递归的逻辑
- 终止条件
144.二叉树的先序遍历
题目链接:
https://leetcode.cn/problems/binary-tree-preorder-traversal/
题目描述:
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
输入:root = [1,null,2,3]
输出:[1,2,3]
思路:
二叉树的先序遍历指的是按照先遍历根节点,再遍历左子树,最后遍历右子树的顺序遍历二叉树。
具体的方法有递归和迭代两种写法。
递归方法:
var preorderTraversal = function(root) {
let re = []
firstOrder(root, re)
return re
};
function preOrder(cur, list){
if(!cur) return
list.push(cur.val)
firstOrder(cur.left, list)
firstOrder(cur.right, list)
}
迭代方法:
利用栈后进先出的特性。开始时先将根节点入栈。接着设置一个循环,每一次循环都将栈顶节点弹出进行操作,之后依次将其右节点和左节点入栈。
var preorderTraversal = function(root) {
if(!root) return []
let re = []
let stack = [root]
while(stack.length > 0){
let cur = stack.pop()
re.push(cur.val)
cur.right && stack.push(cur.right)
cur.left && stack.push(cur.left)
}
return re
};
94.二叉树的中序遍历
题目链接:
https://leetcode.cn/problems/binary-tree-inorder-traversal/
题目描述:
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
输入:root = [1,null,2,3]
输出:[1,3,2]
思路:
后序遍历就是先处理左子树,再处理根节点,最后处理右子树。
递归方法:
var inorderTraversal = function(root) {
let re = []
inOrder(root, re)
return re
};
function inOrder(cur, list){
if(!cur) return
inOrder(cur.left, list)
list.push(cur.val)
inOrder(cur.right, list)
}
迭代方法:
迭代方法的关键就是显示构建和维护栈,可以类比递归来设计。
var inorderTraversal = function(root) {
if(!root) return []
let cur = root
let stack = []
let res = []
while(stack.length || cur){
if(cur){
stack.push(cur)
cur = cur.left
}
else{
cur = stack.pop()
res.push(cur.val)
cur = cur.right
}
}
return res
};
145.二叉树的后序遍历
题目链接:
https://leetcode.cn/problems/binary-tree-postorder-traversal/
题目描述:
给你一棵二叉树的根节点 root
,返回其节点值的 后序遍历 。
输入:root = [1,null,2,3]
输出:[3,2,1]
思路:
递归方法很简单,类似先序和中序遍历。但是迭代方法有一点复杂,复杂的点在于后序遍历处理节点的顺序是左-右-根,但是左右节点都是要由根节点获得,这代表会不止一次访问根节点,究竟哪一次访问根节点时对其进行处理就需要额外的条件来控制。
递归方法:
var postorderTraversal = function(root) {
let re = []
postOrder(root, re)
return re
};
function postOrder(cur, list){
if(!cur) return
postOrder(cur.left, list)
postOrder(cur.right, list)
list.push(cur.val)
}
迭代方法:
我采取的方式是在每个节点入栈时增加一个flag。对某个节点的流程进行分析:这个节点会先入栈(root直接入栈,其他节点是作为父节点的子节点入栈,此时flag=0),之后的某次循环其作为栈顶节点被弹出(此时节点是作为根节点被访问到的),再将该节点和其右左子节点入栈(flag=1)。由于栈的性质,之后出栈符合后序的次序。
对整体流程来说就是:每次弹出节点时检查flag,为0说明这个节点是作为子节点被加入的,它的子节点没有被处理;为1则说明这个节点是作为根节点被加入的,它的子节点之前已经按照次序进栈出栈,现在该处理这个节点了(将其加入结果数组res中)
var postorderTraversal = function(root) {
const stack = []
let res = []
if (!root) return []
stack.push([root,0])
while(stack.length) {
const [node, flag] = stack.pop()
if(flag) {
res.push(node.val)
continue;
}
stack.push([node, 1])
if (node.right) stack.push([node.right, 0])
if (node.left) stack.push([node.left, 0])
};
return res;
};
标签:遍历,cur,javascript,随想录,stack,day14,push,root,节点
From: https://www.cnblogs.com/endmax/p/16966181.html