二叉树

1. 二叉树

树的特殊形式,树的每个节点最多只有两个子节点

  • 满二叉树:一个二叉树的所有非叶子节点都存在左右孩子,并且所有叶子节点都在同一层级上。
  • 完全二叉树:没有满二叉树那么严格,秩序保证最后一个节点之前的节点都齐全即可。

image-20220310170015439

1.前序中序后序遍历

前序遍历:根左右

中序遍历:左根右

后序遍历:左右根

先序:考察到一个节点后,即刻输出该节点的值,并继续遍历其左右子树。(根左右)

中序:考察到一个节点后,将其暂存,遍历完左子树后,再输出该节点的值,然后遍历右子树。(左根右)

后序:考察到一个节点后,将其暂存,遍历完左右子树后,再输出该节点的值。(左右根)

1.1 递归实现

思路与算法

首先我们需要了解什么是二叉树的中序遍历:按照访问左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归的性质,我们可以直接用递归函数来模拟这一过程。

定义 inorder(root) 表示当前遍历到 root 节点的答案,那么按照定义,我们只要递归调用 inorder(root.left) 来遍历root 节点的左子树,然后将 root 节点的值加入答案,再递归调用inorder(root.right) 来遍历 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 {
    private static final int CAPACITY = 10;

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>(CAPACITY);
        PreLookup(root, result);
        return result;

        // return inorderTraversal2(root);
    }

	// 前序遍历
    private void PreLookup(TreeNode node, List<Integer> result) {
        if (node != null) {
            result.add(node.val);
            middlePreLookup(node.left, result);
            middlePreLookup(node.right, result);
        }
    }
    
    // 中序遍历
    private void middleLookup(TreeNode node, List<Integer> result) {
        if (node != null) {
            middlePreLookup(node.left, result);
            result.add(node.val);
            middlePreLookup(node.right, result);
        }
    }
    
    // 后序遍历
    private void afterLookup(TreeNode node, List<Integer> result) {
        if (node != null) {
            middlePreLookup(node.left, result);
            middlePreLookup(node.right, result);
            result.add(node.val);
        }
    }
}

1.2 迭代实现

/**
 * 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 {
    private static final int CAPACITY = 10;

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>(CAPACITY);
        middlePreLookup(root, result);
        return result;

        // return inorderTraversal2(root);
    }

    // 迭代方法 使用栈
    // 中序遍历
	public List<Integer> inorderTraversal2(TreeNode root) {
        List<Integer> result = new ArrayList<>(CAPACITY);
        Stack<TreeNode> stack = new Stack<>();
        // 中序遍历:左根右,出栈顺序:左根右,入栈顺序:右根左
        while (root != null || !stack.isEmpty()) {
            // 当curRoot非空时,一直寻找左叶子节点并将其入栈
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            // 此时root为null, 那么它的父节点为左叶子节点且已入栈,此时需要将它出栈
            root = stack.pop();
            result.add(root.val);
            root = root.right;
        }
        return result;
    }
}

	// 前序遍历
	public List<Integer> inorderTraversal2(TreeNode root) {
        List<Integer> result = new ArrayList<>(CAPACITY);
        Stack<TreeNode> stack = new Stack<>();
        // 前序遍历:根左右,出栈顺序:根左右,入栈顺序:右左根
        while (root != null || !stack.isEmpty()) {
            // 当curRoot非空时,按照右左的顺序进行入栈
            result.add(root.val);
            if (root.right != null) {
                stack.push(root.right);
            }
            if (root.left != null) {
                stack.push(root.left);
            }
            root = stack.pop();
        }
        return result;
    }

	// 后序遍历
	public List<Integer> inorderTraversal2(TreeNode root) {
        List<Integer> result = new ArrayList<>(CAPACITY);
        Stack<TreeNode> stack = new Stack<>();
        // 后序遍历:左右根,出栈顺序:左右根,入栈顺序:根右左
        // 精髓在于先出栈先入队(忘队尾方向)
        // ArrayList.add(int index, E e) 在index处插入元素,原index处及以后的元素右移
        if (root == null) return stack;
        stack.push(root);
        while (!stack.isEmpty()) {
            root = stack.pop();
			result.add(0, root.val);
            if root.left != null stack.push(root.left);
            if root.right != null stack.push(root.right);
        }
        return result;
    }
}
posted @ 2022-03-12 18:04  freryc  阅读(55)  评论(0编辑  收藏  举报