递归遍历
要点
- 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
- 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
- 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
- 都是模板,背就完事
例题
144. 二叉树的前序遍历
/** * @param {TreeNode} root * @return {number[]} */ var preorderTraversal = function(root) { let res = [] const dfs = (root) =>{ if(!root){ return null } // 中左右 res.push(root.val) dfs(root.left) dfs(root.right) } dfs(root) return res };
145. 二叉树的后序遍历
/** * 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 postorderTraversal = function(root) { let res = [] const dfs = (root) =>{ if(!root){ return null } // 左右中 dfs(root.left) dfs(root.right) res.push(root.val) } dfs(root) return res };
94. 二叉树的中序遍历
/** * 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 inorderTraversal = function(root) { let res = [] const dfs = (root) =>{ if(!root){ return null } // 左中右 dfs(root.left) res.push(root.val) dfs(root.right) } dfs(root) return res };
迭代遍历
用栈模拟迭代的做法
144. 二叉树的前序遍历
前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。(反向入栈)
/** * @param {TreeNode} root * @return {number[]} */ var preorderTraversal = function(root) { let res = [] if(!root) return res; const stack = [root]; let cur = null; while(stack.length) { // 中右左入栈 cur = stack.pop(); res.push(cur.val); cur.right && stack.push(cur.right); cur.left && stack.push(cur.left); } return res; };
145. 二叉树的后序遍历
后序遍历是左右中,所以就是中右左再reverse,入栈顺序中左右
/** * 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 postorderTraversal = function(root) { let res = [] if(!root) return res; const stack = [root]; let cur = null; while(stack.length) { // 中左右入栈 cur = stack.pop(); res.push(cur.val); cur.left && stack.push(cur.left); cur.right && stack.push(cur.right); } return res.reverse(); };
94. 二叉树的中序遍历
比较复杂
/** * 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 inorderTraversal = function(root) { let stack = []; let res =[] let cur = root; 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; };
统一遍历法
迭代遍历的代码变化较大,有没有一种统一的方法可以执行便利呢
144. 二叉树的前序遍历
右左中入栈,中左右出栈
// 前序遍历:中左右 // 压栈顺序:右左中 var preorderTraversal = function(root, res = []) { const stack = []; if (root) stack.push(root); while(stack.length) { const node = stack.pop(); if(!node) { res.push(stack.pop().val); continue; } if (node.right) stack.push(node.right); // 右 if (node.left) stack.push(node.left); // 左 stack.push(node); // 中 stack.push(null); }; return res; };
145. 二叉树的后序遍历
中左右入栈,左右中出栈
// 后续遍历:左右中 // 压栈顺序:中右左 var postorderTraversal = function(root, res = []) { const stack = []; if (root) stack.push(root); while(stack.length) { const node = stack.pop(); if(!node) { res.push(stack.pop().val); continue; } stack.push(node); // 中 stack.push(null); if (node.right) stack.push(node.right); // 右 if (node.left) stack.push(node.left); // 左 }; return res; };
94. 二叉树的中序遍历
右中左入栈,左右中出栈
// 中序遍历:左中右 // 压栈顺序:右中左 var inorderTraversal = function(root, res = []) { const stack = []; if (root) stack.push(root); while(stack.length) { const node = stack.pop(); if(!node) { res.push(stack.pop().val); continue; } if (node.right) stack.push(node.right); // 右 stack.push(node); // 中 stack.push(null); if (node.left) stack.push(node.left); // 左 }; return res; };