【数据结构】二叉树 | 深度优先遍历之非递归法

115 阅读2分钟

非递归法,也就是迭代法,其实是用stack栈数据机构来模拟递归方法的过程
对于比较简单的递归法,可以用栈来模拟,比如说二叉树的前中后序遍历就是必须先掌握的

题目一 前序遍历144. 二叉树的前序遍历 - 力扣(LeetCode)

思路

  1. 前序遍历是先处理中,再处理左,最后处理右
  2. 首先将根节点入栈,弹出根节点,处理节点
  3. 处理当前节点包括:(1)将节点值保存;(2)将其(非空)右节点入栈;(3)将其(非空)左节点入栈
  4. 当stack不为空,循环3,直到栈为空

代码

  • 注意:特殊情况处理,当root节点为空时,返回空数组
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        ArrayList<Integer> result = new ArrayList<>();
        if(root == null) {
            return result;
        }
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            result.add(node.val);
            if(node.right != null) stack.push(node.right);
            if(node.left != null) stack.push(node.left);
        }
        return result;
    }
}

题目二 中序遍历94. 二叉树的中序遍历 - 力扣(LeetCode)

递归法代码

  • 将递归函数稍微调整位置即可
前序中序后序
preorder(node.left,result);result.add(node.val);postorder(node.left,result);
result.add(node.val);inorder(node.left,result);postorder(node.right,result);
preorder(node.right,result);inorder(node.right,result);result.add(node.val);
// 递归法-中序
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        ArrayList<Integer> result = new ArrayList<>();
        if(root == null) {
            return result;
        }
        inorder(root,result);
        return result;
    }
    public void inorder(TreeNode node, ArrayList<Integer> result) {
        if(node == null) {
            return;
        }
        inorder(node.left,result);
        result.add(node.val);
        inorder(node.right,result);
    }
}

// 递归法-后序
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        if(root == null) {
            return res;
        }
        postorder(root,res);
        return res;
    }
    public void postorder(TreeNode node,ArrayList<Integer> res) {
        if(node == null) {
            return;
        }
        postorder(node.left,res);
        postorder(node.right,res);
        res.add(node.val);
    }
}

思路

  1. 中序遍历,先处理左节点,再处理中节点,最后处理右节点
  2. 首先将根节点入栈,弹出根节点,处理节点
  3. 处理节点:(1)节点的(非空)右节点入栈;(2)节点入栈+null入栈;(3)节点的(非空)左节点入栈
  4. 弹出栈顶元素,重复3,直到遇到xxx

在3(2)节点入栈时应该在后面标记null,表示这个节点已经搜索过了
第4步,弹出栈顶元素,若遇到null,则把栈顶元素弹出记录res并continue;如果没有遇到null,说明该元素还没有访问过,重复3

代码

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        ArrayList<Integer> res = new ArrayList<>();
        if(root == null) {
            return res;
        }
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if(node == null) {
                res.add(stack.pop().val);
                continue;
            }
            if(node.right != null) stack.push(node.right);
            stack.push(node);
            stack.push(null);
            if(node.left != null) stack.push(node.left);
        }
        return res;        
    }
}

题目三 后序遍历145. 二叉树的后序遍历 - 力扣(LeetCode)

思路

  1. 后序遍历,先处理左节点,再处理右节点,最后处理中节点
  2. 首先将根节点入栈,弹出根节点,处理节点
  3. 处理节点:(1)节点入栈+null入栈;(2)节点的(非空)右节点入栈;(3)节点的(非空)左节点入栈
  4. 弹出栈顶元素,重复3,直到遇到xxx

在3(1)节点入栈时应该在后面标记null,表示这个节点已经搜索过了
弹出栈顶元素,若遇到null,把把栈顶元素弹出记录res并continue;如果没有遇到null,说明该元素还没有访问过,重复3

问题

  • 如果记录res后没有continue,有什么问题?此时继续往下执行,又把node入栈了,逻辑出大问题,所以,一定要记得退出continue当前循环,处理下一个弹出的元素

代码

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        if(root == null) {
            return res;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if(node == null) {
                res.add(stack.pop().val);
                continue;
            }
            stack.push(node);
            stack.push(null);
            if(node.right != null) stack.push(node.right);
            if(node.left != null) stack.push(node.left);
        }
        return res;
    }
}