二叉树的前序,中序,后序遍历

概述

树 是一种经常用到的数据结构,用来模拟具有树状结构性质的数据集合。

树里的每一个节点有一个值和一个包含所有子节点的列表。从图的观点来看,树也可视为一个拥有N 个节点和N-1 条边的一个有向无环图。

二叉树是一种更为典型的树状结构。如它名字所描述的那样,二叉树是每个节点最多有两个子树的树结构,通常子树被称作“左子树”和“右子树”。

树的遍历 - 介绍

前序遍历

前序遍历首先访问根节点,然后遍历左子树,最后遍历右子树。

中序遍历

中序遍历是先遍历左子树,然后访问根节点,然后遍历右子树。
通常来说,对于二叉搜索树,我们可以通过中序遍历得到一个递增的有序序列。

后序遍历

后序遍历是先遍历左子树,然后遍历右子树,最后访问树的根节点。

二叉树的前序遍历

给定一个二叉树,返回它的前序遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [1,2,3]

2种解法

解法1:递归

递归的方法很容易实现,也很容易理解:我们先访问根节点,然后递归访问左子树,再递归访问右子树,即实现了根->左->右的访问顺序,因为使用的是递归方法,所以每一个子树都实现了这样的顺序。

public List preorderTraversal(TreeNode root) {
    List res = new ArrayList<>();
    preorder(root, res);
    return res;
}

private void preorder(TreeNode root, List res) {
    if (root == null) {
        return;
    }
    res.add(root.val);
    preorder(root.left, res);
    preorder(root.right, res);
}

解法2:迭代法

在迭代法中,我们使用栈来实现。由于出栈顺序和入栈顺序相反,所以每次添加节点的时候先添加右节点,再添加左节点。这样在下一轮访问子树的时候,就会先访问左子树,再访问右子树:

public List preorderTraversal(TreeNode root) {
    List output = new LinkedList<>();
    if (root == null) {
        return output;
    }
    
    Stack stack = new Stack<>();
    stack.push(root);
    
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        output.add(node.val);
        if (node.right != null) {
            stack.push(node.right);
        }
        if (node.left != null) {
            stack.push(node.left);
        }
    }
    return output;
}
二叉树的中序遍历

给定一个二叉树,返回它的中序遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [1,2,3]

2种解法

解法1:递归

递归的方法很容易实现,也很容易理解:先访问左子树,再访问根节点,再访问右子树,即 左->根->右

public List inorderTraversal(TreeNode root) {
    List res = new ArrayList<>();
    inorder(root, res);
    return res;
}
private void inorder(TreeNode root, List res) {
    if (root == null) {
        return;
    }
    inorder(root.left, res);
    res.add(root.val);
    inorder(root.right, res);
}

解法2:迭代法

中序遍历的迭代法要稍微复杂一点,因为最先遇到的根节点不是最先访问的,我们需要先访问左子树,再回退到根节点,再访问根节点的右子树,这里的一个难点是从左子树回退到根节点的操作,虽然可以用栈来实现回退,但是要注意在出栈时保存根节点的引用,因为我们还需要通过根节点来访问右子树:

public List inorderTraversal(TreeNode root) {
    List res = new ArrayList<>();
    Stack stack = new Stack<>();
    TreeNode curr = root;
    while (curr != null || !stack.isEmpty()) {
        while (curr != null) {
            stack.push(curr);
            curr = curr.left;
        }
        curr = stack.pop();
        res.add(curr.val);
        curr = curr.right;
    }
    return res;
}
二叉树的后序遍历

给定一个二叉树,返回它的后序遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [1,2,3]

2种解法

解法1:递归

递归的方法很容易实现,也很容易理解:对于后序遍历,就是先访问左子树,再访问右子树,再访问根节点,即 左->右->根:

public List postorderTraversal(TreeNode root) {
    List res = new ArrayList<>();
    postorder(root, res);
    return res;
}
private void postorder(TreeNode root, List res) {
    if (root == null) {
        return;
    }
    postorder(root.left, res);
    postorder(root.right, res);
    res.add(root.val);
}

解法2:迭代法

从根节点开始依次迭代,弹出栈顶元素输出到输出列表中,然后依次压入它的所有孩子节点,按照从上到下、从左至右的顺序依次压入栈中。
因为深度优先搜索后序遍历的顺序是从下到上、从左至右,所以需要将输出列表逆序输出。

public List postorderTraversal(TreeNode root) {
    LinkedList stack = new LinkedList<>();
    LinkedList output = new LinkedList<>();
    if (root == null) {
      return output;
    }

    stack.add(root);
    while (!stack.isEmpty()) {
      TreeNode node = stack.pollLast();
      output.addFirst(node.val);
      if (node.left != null) {
        stack.add(node.left);
      }
      if (node.right != null) {
        stack.add(node.right);
      }
    }
    return output;
}

你可能感兴趣的:(数据结构,java)