高频刷题-94, 144, 145 二叉树的前序中序后序遍历

二叉树的preorder, inorder and postorder 遍历,在leetcode中都有对应的题。下面一起介绍,同时介绍recursion和iteration两种方式实现。

 

https://leetcode.com/problems/binary-tree-inorder-traversal/

https://leetcode.com/problems/binary-tree-preorder-traversal/

https://leetcode.com/problems/binary-tree-postorder-traversal/

 

首先看中序遍历,最简单的是递归实现,很好理解,下面是实现代码(这一套实现可以作为前序、中序、后序遍历的模板):

// 中序遍历
public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        inorderHelper(root, res);
        return res;
    }
    
    private void inorderHelper(TreeNode root, List res) {
        if (root != null) {
            
            if (root.left != null) inorderHelper(root.left, res);
            res.add(root.val); 
            if (root.right != null) inorderHelper(root.right, res);
        }
    }

 

相应的,作为对比,给出前序和后序遍历的实现:

// 前序遍历
public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        preorderHelper(root, res);
        return res;
    }
    
    private void preorderHelper(TreeNode root, List res) {
        if (root != null) {
            res.add(root.val);
            if (root.left != null) preorderHelper(root.left, res);
            if (root.right != null) preorderHelper(root.right, res);
        }
    }

后序遍历:

// 后序遍历
public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        postorderHelper(root, res);
        return res;
    }
    
    private void postorderHelper(TreeNode root, List res) {
        if (root != null) {
            if (root.left != null) postorderHelper(root.left, res);
            if (root.right != null) postorderHelper(root.right, res);
            res.add(root.val);
        }
    }

 

如果使用iteration遍历,三种访问方式都可以采用stack实现。可以对比着看,具体实现看代码注释。

public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>(); // 返回结果
        
        Stack<TreeNode> stack = new Stack<>(); 
        TreeNode curr = root;
        pushItselfAndAllLeft(curr, stack);  // 将自己和它的所有左节点全部入栈
        
        while(!stack.isEmpty()) {
            
            TreeNode tmp = stack.pop();  // 出栈,最晚进的最先出
            
            res.add(tmp.val);  
            
            if (tmp.right != null) pushItselfAndAllLeft(tmp.right, stack);  // 访问一次右子树的自生和全部左节点
        }
        
        return res;
    }
        
        
        private void pushItselfAndAllLeft(TreeNode curr, Stack<TreeNode> stack) {
            while (curr != null) {
                stack.push(curr);
                curr = curr.left;
            }
        }

前序遍历:

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>(); // 返回结果
        
        if (root == null) return res;  // 防止将null值push到stack中
        
        Stack<TreeNode> stack = new Stack<>(); 
        TreeNode curr = root; 
        stack.push(curr);  // push 根节点
        
        while(!stack.isEmpty()) {
            TreeNode tmp = stack.pop();
            res.add(tmp.val);
            if (tmp.right != null) stack.push(tmp.right);  // 因为栈具有后入先出的特性,所以先push右子树
            if (tmp.left != null) stack.push(tmp.left);
        } 
        return res;
    }

后序遍历则稍微复杂一点,主要是涉及到一个reverse操作,具体可以看实现中的注释:

public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>(); // 返回结果
        
        if (root == null) return res;  // 防止将null值push到stack中
        
        Stack<TreeNode> stack = new Stack<>(); 
        TreeNode curr = root; 
        stack.push(curr);  // push 根节点
        
        while(!stack.isEmpty()) {
            TreeNode tmp = stack.pop();
            // 后续遍历顺序是左,右,顶点,所以此时插入的时候都插到最前面,相当于reverse.
            // 可以理解为遍历 顶点、右、左,得到的结果再reverse
            res.add(0, tmp.val);  
            if (tmp.left != null) stack.push(tmp.left);  // 因为栈具有后入先出的特性,所以先push右子树
            if (tmp.right != null) stack.push(tmp.right);
        } 
        return res;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值