算法中的二叉树问题(简单)


树结构:

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

一、中序遍历

1.递归方法

  • 首先遍历左子树
  • 再遍历当前结点
  • 最后遍历右子树
class Solution {
    
    
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new ArrayList<>();
        process(root,list);
        return list;

    }

    public void process(TreeNode root,List<Integer> list){
    
    
        if(root==null) return;
        process(root.left,list);
        list.add(root.val);
        process(root.right,list);
    }
}

2.非递归法

需要一个辅助栈

  • 若当前结点不为空,则把当前的节点的所有左孩子加入栈中
  • 若当前结点为空,说明遇到了叶子结点,从栈中弹出一个结点,对这个结点的右孩子做相同的操作
  • 重复上述操作直到栈为空且当前结点为空。
public List<Integer> inorderTraversal(TreeNode root) {
    
    
        Stack<TreeNode> stack = new Stack<>();
        List<Integer> ans = new ArrayList<>();
        if(root==null) return ans;
        stack.push(root);
        root = root.left;
        while(!stack.isEmpty()||root!=null){
    
    
            if(root!=null){
    
    
                stack.push(root);
                root = root.left;
            }else{
    
    
                root = stack.pop();
                ans.add(root.val);
                root = root.right;
            }
        }
        return ans;
    }

二、先序遍历

1.递归方法

  • 首先遍历当前结点
  • 然后遍历左子树
  • 最后遍历右子树
class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new ArrayList<>();
        process(root,list);
        return list;
    }

    public void process(TreeNode root,List<Integer> list){
    
    
        if(root==null) return;
        list.add(root.val);
        process(root.left,list);
        process(root.right,list);
    }
}

2.非递归方法

需要一个辅助栈,首先把头结点放进栈中

  • 每次从栈中弹出一个结点cur
  • 操作cur
  • 先把cur右孩子压入栈中,再把cur左孩子压入栈中(若存在的话)
  • 重复以上步骤直到栈为空
class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        Stack<TreeNode> stack = new Stack<>();
        List<Integer> ans = new ArrayList<>();
        if(root==null) return ans;
        stack.push(root);
        while(!stack.isEmpty()){
    
    
            root = stack.pop();
            ans.add(root.val);
            if(root.right!=null) stack.push(root.right);
            if(root.left!=null) stack.push(root.left);
        }
        return ans;
    }

}

数学理解:
每次循环先处理当前结点,并且把他的右孩子,左孩子依次入栈,出栈的时候就能保证这三个结点一定有中 左 右的顺序,推广到整颗书上的所有结点都会具有这样的关系,因此就保证了先序遍历。

三、后序遍历

1.递归方法

  • 首先遍历左子树
  • 然后遍历右子树
  • 最后遍历当前结点
class Solution {
    
    
    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        List<Integer> ans = new ArrayList<>();
        process(root,ans);
        return ans;
    }

    public void process(TreeNode root,List<Integer> list){
    
    
        if(root==null) return;
        process(root.left,list);
        process(root.right,list);
        list.add(root.val);
    }
}

2.非递归法

根据之前的先序遍历,我们只需要改变左右孩子的入栈顺序,就能将中 左 右的顺序改成中 右 左,最后再反向遍历中 右 左就可以得到正确的后续遍历。

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

猜你喜欢

转载自blog.csdn.net/qq_45733304/article/details/125018000