• 数据结构——二叉树遍历之“递归与非递归遍历”


    简述

    二叉树的遍历分为先序遍历、中序遍历和后序遍历。如下图所示:

    递归遍历

    private void bianli1(List<Integer> list, TreeNode root) {
        // 先序遍历
        if (root == null) {
            return;
        }
        list.add(root.val);
        bianli1(list, root.left);
        bianli1(list, root.right);
    }
    
    private void bianli2(List<Integer> list, TreeNode root) {
        // 中序遍历
        if (root == null) {
            return;
        }
        bianli2(list, root.left);
        list.add(root.val);
        bianli2(list, root.right);
    }
    
    private void bianli3(List<Integer> list, TreeNode root) {
        // 后序遍历
        if (root == null) {
            return;
        }
        bianli3(list, root.left);
        bianli3(list, root.right);
        list.add(root.val);
    }

    递归遍历实现比较简单,递归利用函数栈来保存信息。

    非递归遍历

    非递归需要额外自己申请数据结构来代替函数栈。

    先序遍历:

    1.申请一个栈 stack。然后将头结点 head 压入 stack 中。
    2.从 stack 中弹出栈顶结点,记为 cur,然后打印 cur 结点的值,再将 cur 的右孩子(非空的话)和左孩子(非空的话)分别压入栈中。
    3.不断重复步骤 2,直到栈 stack 为空,全部过程结束。

    中序遍历:

    1.申请一个栈 stack。初始时,令变量 cur=head。
    2.先把 cur 结点压入栈中,然后依次把左边界压入栈中,即不停的令 cur=cur.left,重复该步骤。
    3.不断重复步骤 2,直到 cur 为空为止,此时从 stack 中弹出栈顶元素,记为 node。打印 node 的值,并将 cur=node.right,然后继续重复步骤2。
    4.当 stack 为空且 cur 为空时,整个过程停止。

    后序遍历:

    1.申请一个栈,记为s1,然后将头结点 head 压入 s1 中。
    2.从 s1 中弹出的结点记为 cur,然后依次将 cur 的左孩子和右孩子压入 s1 中。
    3.整个过程中 s1 所弹出的结点都压入 s2 中。
    4.不断重复步骤2-3,直到 s1 为空为止。
    5.从 s2 中弹出结点并打印,打印的顺序就是后序遍历的顺序。

    源码实现:

    /**
     * 先序遍历
     */
    private static void xianxu(List<Integer> list, TreeNode root) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.add(root);
        while (!stack.isEmpty()) {
            root = stack.pop();
            list.add(root.val);
            if (root.right != null) {
                stack.push(root.right);
            }
            if (root.left != null){
                stack.push(root.left);
            }
    
        }
    }
    /**
     * 中序遍历
     */
    private static void zhongxu(List<Integer> list, TreeNode root) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        while (!stack.isEmpty() || root!=null) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            }else {
                root = stack.pop();
                list.add(root.val);
                root = root.right;
            }
        }
    }
    /**
     * 后序遍历
     */
    private static void houxu(List<Integer> list, TreeNode root) {
        Stack<TreeNode> stack1 = new Stack<TreeNode>();
        Stack<TreeNode> stack2 = new Stack<TreeNode>();
        stack1.add(root);
        while (!stack1.isEmpty()) {
            root = stack1.pop();
            stack2.push(root);
            if (root.left != null) {
                stack1.push(root.left);
            }
            if (root.right != null) {
                stack1.push(root.right);
            }
        }
        while (!stack2.isEmpty()) {
            list.add(stack2.pop().val);
        }
    }

    参考资料

    [1] 程序员代码面试, 第三章 - 二叉树问题

  • 相关阅读:
    页面反向映射之文件页面
    页面反向映射之匿名页面
    cp so文件导致进程SIGBUS或者SEGV原因分析
    由systemtap直接修改内核代码段想到的
    epoll的内核实现
    从一些现象看printf的缓冲机制
    Linux由浅入深学习 (转)
    每天一个Linux命令 (转)
    Redis与数据库同步问题
    PHP使用文件流下载文件方法(附:解决下载文件内容乱码问题)
  • 原文地址:https://www.cnblogs.com/zhengbin/p/6569068.html
Copyright © 2020-2023  润新知