LeetCode刷题日记之二叉树的迭代、递归遍历

29 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情
1.二叉数的前序遍历

题目描述

image.png

解题思路

1.首先我们需要理解二叉树的前序遍历,遍历顺序为中、左、右
2.我们可以使用递归法来实现二叉树的前序遍历
3.递归法三要素:确定递归函数的参数和返回值、确定递归终止条件、确定单层逻辑
4.只要确定好了上述三要素,可以很容易的写出一下代码。

var preorderTraversal = function(root) {
    let result = []
    const preOder = (node) => {  // 递归参数 无返回值
        if(node == null) { // 递归终止条件
            return
        }
        result.push(node.val) // 单层逻辑
        node.left&&preOder(node.left)
        node.right&&preOder(node.right)
    }
    preOder(root)
    return result
};

同样我们只需要改一下单层处理逻辑可以很轻易的写出二叉树的中序遍历和后序遍历

// 中序遍历 左中右
var preorderTraversal = function(root) {
    let result = []
    const preOder = (node) => {  // 递归参数 无返回值
        if(node == null) { // 递归终止条件
            return
        }
        
        node.left&&preOder(node.left)
        result.push(node.val) // 单层逻辑
        node.right&&preOder(node.right)
    }
    preOder(root)
    return result
};

// 后续遍历  左右中
var preorderTraversal = function(root) {
    let result = []
    const preOder = (node) => {  // 递归参数 无返回值
        if(node == null) { // 递归终止条件
            return
        }
        
        node.left&&preOder(node.left)
        node.right&&preOder(node.right)
        result.push(node.val) // 单层逻辑
    }
    preOder(root)
    return result
};

除此之外,我们还可以使用迭代的方式来解决该问题。
使用迭代法我们需要使用一个辅助栈来存放节点,前序遍历我们可以按照根右左的方式把节点入栈,这样出栈的顺序就成了中左右的顺序了,可以很简单的写出以下代码。

var preorderTraversal = function(root) {
    const stack = []
   const result = []
   if(root == null) return []
   stack.push(root)
   while(stack.length){
       const node = stack.pop();
       // 前序遍历 中左右
       result.push(node.val)
       node.right&&stack.push(node.right) // 栈先入后出  所以右子树先入
       node.left&&stack.push(node.left)
   }
   return result
};

在前序遍历的基础上稍微改一下可以写出后续遍历

var postorderTraversal = function(root) {
// 迭代

   if(root === null) return []
   const stack = []
   const res = []
   stack.push(root)
   while(stack.length){
       const node = stack.pop()
   
       if(node.left) stack.push(node.left)
       if(node.right) stack.push(node.right)
       res.push(node.val)
       
   }
   return res.reverse()
};

中序遍历又稍微有些不同,因为要先访问左子节点,再访问根节点,右子节点,遍历时需要一直到最左子节点开始回溯。

var inorderTraversal = function(root) {
    const res= []
     const stack = [];
     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;
};

除此之外,迭代法还有一种统一的写法

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;
};