数据结构与算法(一):有关二叉树遍历的一些算法问题(前中后序、层次遍历)

一、前言

学习二叉树也有一段时间了,但一直没有系统的整理一些最基础的算法问题,这篇文章就当是个总结吧。二叉树的数据结构相信大家已经烂熟于心了,在此不多说了,直接上代码。

二、先从递归说起

二叉树最明显的特征就是递归结构,很多关于二叉树的算法题都与递归扯不开关系。

1.递归前中后序遍历二叉树:

private List<Integer> inorderTraversal(TreeNode root) {
    //我们用一list来存储结果
    List<Integer> res = new ArrayList<>();
    visit(root, res);
    return res;
}

private void visit(TreeNode root, List<Integer> res) {
    if (root != null) {
        //对结果集进行添加
        res.add(root.val);
        //递归左子树
        if (root.left != null) {
            visit(root.left, res);
        }
        //递归右子树
        if (root.right != null) {
            visit(root.right, res);
        }
    }
}

而对于中序和后序遍历,只是对结果集进行添加这一步的位置不同。中序是一种左中右的顺序,而后续则是左右中的顺序。

2.递归层次遍历二叉树

层次遍历二叉树相对前面来说有些麻烦,我们需要之定一个变量来记录当前层次:

private List<List<Integer>> levels = new ArrayList<>();  //结果集
private List<List<Integer>> levelOrder(TreeNode root) {
    if (root == null) {
        return levels;
    }
    //默认从第0层开始遍历
    helper(root, 0);
    return levels;
}

private void helper(TreeNode root, int level) {
    //如果当前层的元素已经全部遍历完了,就添加进结果集
    if (levels.size() == level) {
        levels.add(new ArrayList<>(level));
    }
    //从根结点开始添加
    levels.get(level).add(root.val);
    //递归左子树并给层+1,因为孩子结点是位于下一层的
    if (root.left != null) {
        helper(root.left, level + 1);
    }
    //同理
    if (root.right != null) {
        helper(root.right, level + 1);
    }
}

三、进阶到非递归遍历

非递归遍历是个难点,同样也是重点,需要反复的去理解。

1.非递归前序遍历二叉树:

private List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    LinkedList<TreeNode> stack = new LinkedList<>();
    TreeNode curr = root;
    while (curr != null || !stack.isEmpty()) {
        while (curr != null) {
            //一开始将根结点加入结果集
            res.add(curr.val);
            //进行入栈操作并遍历左子树
            stack.push(curr);
            curr = curr.left;
        }
        //出栈并遍历右子树
        curr = stack.pop();
        curr = curr.right;
    }
    return res;
}

2.非递归中序遍历二叉树:

private List<Integer> inorderTraversal2(TreeNode root) {
    //结果集
    List<Integer> res = new ArrayList<>();
    //非递归遍历的核心就是利用栈这一数据结构
    LinkedList<TreeNode> stack = new LinkedList<>();
    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.right是null,所以执行完第一次后继续进行弹栈操作。
        //第二次的时候这里就是是最左边的元素的父结点的右孩子了
        curr = curr.right;
    }
    return res;
}

3.非递归后续遍历二叉树:

private List<Integer> postorderTraversal(TreeNode root) {
    LinkedList<TreeNode> stack = new LinkedList<>();
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        //逆向思维,每次都把后面的元素加入到第一位
        //先序遍历是根左右,后续遍历是左右根
        //把先序遍历的根左右变成根右左,然后在逆过来就行
        res.add(0, node.val);
        if (node.left != null) {
            stack.push(node.left);
        }
        if (node.right != null) {
            stack.push(node.right);
        }
    }
    return res;
}

4.非递归层次遍历:

利用队列这一数据结构来存储信息

private List<List<Integer>> levelOrder2(TreeNode root) {
    List<List<Integer>> result = new ArrayList<>();
    if (root == null) {
        return result;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()) {
        //保存每一层的信息
        List<Integer> level = new ArrayList<>();
        int level_length = queue.size();
        for (int i = 0; i < level_length; i++) {
            TreeNode node = queue.remove();
            level.add(node.val);
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        //将每一层的信息添加到结果集中
        result.add(level);
    }
    return result;
}

猜你喜欢

转载自blog.csdn.net/laobanhuanghe/article/details/106050443