备战实习记录之【树与二叉树篇】2——二叉树的前中后序遍历

 

2 使用栈实现二叉树的前中后序遍历

2.1 前序遍历(144.二叉树的前序遍历)

2.1.1 解题思路

2.1.2 Java实现(栈——迭代)

2.1.3 Java实现(递归)

2.2 中序遍历(94. 二叉树的中序遍历)

2.2.1 解题思路

2.2.2 Java实现(栈——迭代)

2.2.3 Java实现(递归)

2.3 后序遍历(145. 二叉树的后序遍历)

2.3.1 解题思路

2.3.2 Java实现(栈——迭代)

2.3.3 Java实现(递归)

2.4 迭代法实现前序、中序、后序遍历的统一解法(重要)

2.4.1 中序遍历

2.4.2 前序遍历

2.4.3 后序遍历


2 使用栈实现二叉树的前中后序遍历

2.1 前序遍历(144.二叉树的前序遍历)

2.1.1 解题思路

二叉树的前序遍历即先遍历根节点、再遍历左节点、最后遍历右节点。

  • 先把每一个根节点加入栈,弹出放入遍历集合中。
  • 找到当前结点的右节点,入栈操作。
  • 再找到当前结点的左节点,入栈操作。

重复以上操作,直至栈为空,证明所有元素已被遍历完。

注意:

前序遍历的重点,就是先让右节点入栈、再让左节点入栈

这样基于栈 先进后出的特点,会实现出栈顺序为:根节点——左节点——右节点。

2.1.2 Java实现(栈——迭代)

/**
 * 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<>();
        List<Integer> res = new ArrayList<>();
        stack.push(root);
        while(!stack.empty()){
            TreeNode node = stack.pop();   //中
            if(node!= null){
                res.add(node.val);
            }else{
                continue;
            }
            stack.push(node.right);   //左
            stack.push(node.left);   //右

        }
        return res;
    }
}

2.1.3 Java实现(递归)

/**
 * 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) {
        List<Integer> res = new ArrayList<>();
        preorder(root,res);
        return res;
    }
    public void preorder(TreeNode root,List<Integer> res){
        if (root == null) {
            return;
        }
        res.add(root.val);
        preorder(root.left,res);
        preorder(root.right,res);
    }
   
}

2.2 中序遍历94. 二叉树的中序遍历

2.2.1 解题思路

二叉树的中序遍历与前序遍历差别较大。

主要原因在于:

  • 前序遍历中,从root节点开始,访问顺序与遍历顺序一致。因此直接按照访问顺序处理即可。
  • 但中序遍历中,先访问的是root节点,但是遍历顺序是从左节点先开始。
  1. 因此从root节点开始,先一层一层向下访问,将左节点全部入栈。直至左子树的最后一层。
  2. 此时依次出栈(即遍历结果——加入list集合中),并访问右节点。

基于栈 先进后出的原理,此处入栈的顺序为:根节点——左节点,出栈之后再将右节点入栈。因此,出栈后的顺序即为左中右。

代码中保证了,有左节点先遍历左节点,没有左节点,则遍历根节点。

遍历完根节点才让当前节点的右节点入栈。

2.2.2 Java实现(栈——迭代)

/**
 * 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> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();
        while(!stack.empty() || cur!=null){
            if(cur!=null){
                stack.push(cur);
                cur = cur.left;   //左
            }else{
                cur = stack.pop();
                res.add(cur.val);   //中
                cur = cur.right;   //右
            }
        }
        return res;
    }
}

2.2.3 Java实现(递归)

/**
 * 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> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        inorder(root,res);
        return res;
    }
    public void inorder(TreeNode root,List<Integer> res){
        if (root == null) {
            return;
        }
        inorder(root.left,res);
        res.add(root.val);
        inorder(root.right,res);
    }
}

2.3 后序遍历145. 二叉树的后序遍历

2.3.1 解题思路

2.3.2 Java实现(栈——迭代)

解法一:

前序遍历的顺序是 中左右 。后序遍历的顺序是左右中。

则参考前序遍历的递归解法,先遍历为中右左(只需使左节点先入栈,右节点后入栈即可)。

再将中右左的结果反转一下。就可以得到 左右中的遍历顺序。

/**
 * 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> postorderTraversal(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        List<Integer> res = new ArrayList<>();
        while(!stack.empty()){
            TreeNode node = stack.pop();
            if(node!=null){
                res.add(node.val);
            }else{
                continue;
            }
            stack.push(node.left);
            stack.push(node.right);
        }
        Collections.reverse(res);
        return res;
    }
}

解法二:

  1. 首先将根节点入栈
  2. 再把根节点的左子树入栈,一层一层遍历,直到左子树的底层
  3. 得到栈顶元素的值,先不访问,判断栈顶元素是否存在右节点,如果存在并且没有被访问,则将右节点入栈,否则,就访问栈顶元素

需要注意的点就在于需要一个前驱指针,用于判断是否该节点的右节点被访问过。

/**
 * 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> postorderTraversal(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        List<Integer> res = new ArrayList<>();
        TreeNode cur = root;
        TreeNode prev = null;
        while(cur!=null || !stack.empty()){
            while(cur!=null){
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            if(cur.right==null || cur.right==prev){
                res.add(cur.val);
                prev = cur;
                cur = null;
            }else{
                stack.push(cur);
                cur = cur.right;
            }
        }
        return res;
    }
}

2.3.3 Java实现(递归)

/**
 * 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> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        postorder(root,res);
        return res;
    }
    public void postorder(TreeNode root,List<Integer> res){
        if (root == null) {
            return;
        }
        postorder(root.left,res);
        postorder(root.right,res);
        res.add(root.val);
    }
    
}

2.4 迭代法实现前序、中序、后序遍历的统一解法(重要)

2.4.1 中序遍历

使用栈的话,「无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况」

「那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。」

如何标记呢,「就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。」 这种方法也可以叫做标记法。

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

        return res;
    }
}

2.4.2 前序遍历

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

        return res;
    }
}

2.4.3 后序遍历

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

猜你喜欢

转载自blog.csdn.net/paranior/article/details/115266364