zoukankan      html  css  js  c++  java
  • 用递归和非递归方式实现二叉树的先序、中序、后序遍历

     

     

    树结构定义

        public class TreeNode {
            public int val;
            public TreeNode left;
            public TreeNode right;
    
            public TreeNode(int x) {
                this.val = x;
            }
        }

     

    先序、中序、后序指的是根节点,先序:根左右;中序:左根右;后序:左右根。

    递归方式如下,之间的差别就是调整了输出语句的位置。

        public void preOrderRecur(TreeNode root) {
            if (root == null)
                return;
            System.out.println(root.val);
            preOrderRecur(root.left);
            preOrderRecur(root.right);
        }
    
        public void inOrderRecur(TreeNode root) {
            if (root == null)
                return;
            inOrderRecur(root.left);
            System.out.println(root.val);
            inOrderRecur(root.right);
        }
    
        public void posOrderRecur(TreeNode root) {
            if (root == null)
                return;
            posOrderRecur(root.left);
            posOrderRecur(root.right);
            System.out.println(root.val);
        }
    View Code

     

    用递归方法解决的问题都能用非递归的方法实现。因为递归方法利用了函数栈来保存信息,如果用自己申请的数据结构代替函数栈,也能实现相同功能。

    非递归的先序遍历:

    1、申请栈,头节点入栈;

    2、弹出栈顶并打印,右孩子入栈(不null),左孩子入栈(不null);

    3、不断重复步骤2,直到栈空。

        public void preOrderUnRecur(TreeNode root) {
            if (root == null)
                return;
            Stack<TreeNode> s = new Stack<TreeNode>();
            s.push(root);
            while (!s.isEmpty()) {
                root = s.pop();
                System.out.println(root.val);
                if (root.right != null)
                    s.push(root.right);
                if (root.left != null)
                    s.push(root.left);
            }
        }

     

    非递归的中序遍历:

    1、申请栈,令cur=root;

    2、cur入栈,不断令cur=cur.left并入栈;

    3、cur==null时,从栈中弹出一个节点node并打印,令cur=node.right,重复步骤2;

    4、重复2、3直到栈空且cur空。

        public void inOrderUnRecur(TreeNode root) {
            if (root == null)
                return;
            Stack<TreeNode> s = new Stack<TreeNode>();
            while (!s.isEmpty() || root != null) {
                if (root != null) {
                    s.push(root);
                    root = root.left;
                } else {
                    root = s.pop();
                    System.out.println(root.val);
                    root = root.right;
                }
            }
        }

     

    非递归的后序遍历:

    首先是两个栈的实现方式,比较好理解:

    1、申请栈s1,s2,头节点 入s1;

    2、s1中弹出节点记为cur,cur压入s2,cur左右孩子依次压入s1;

    3、重复2直到s1为空;

    4、从s2中不断出栈并打印。

    解释:每颗子树的头节点都最先从s1中弹出,然后把该节点的孩子按照先左再右的顺序压入s1,

    那么从s1中弹出的顺序就是先右再左,总的顺序就是中右左,则从s2中弹出的顺序是左右中(逆s1)。

        // two stacks
        public void posOrderUnRecur1(TreeNode root) {
            if (root == null)
                return;
            Stack<TreeNode> s1 = new Stack<TreeNode>();
            Stack<TreeNode> s2 = new Stack<TreeNode>();
            s1.push(root);
            while (!s1.isEmpty()) {
                // 每颗子树的头节点都最先从s1中弹出
                root = s1.pop();
                s2.push(root);
                // 先左后右压入,总的出栈顺序为中右左,则s2出栈顺序为左右中
                if (root.left != null)
                    s1.push(root.left);
                if (root.right != null)
                    s1.push(root.right);
            }
            while (!s2.isEmpty())
                System.out.println(s2.pop().val);
        }

     

    然后是一个栈的实现方式:

    1、申请栈,头节点入栈,设置变量h和c,h代表最近一次弹出并打印的节点,c代表栈顶节点,初试时h为头节点,c为null;

    2、令c=stack.peek(); //即令c等于栈顶节点,但栈顶不弹出,分三种情况:

    Ⅰ  如果 c.left != null,且 h != c.left,且 h!=c.right,则c的左孩子入栈。

    解释:h代表最近一次弹出并打印的节点,如果 h==c.left 或者 h==c.right,说明c的左子树和右子树已经打印完毕,

    不应该再把c的左孩子入栈。否则,说明c的左子树还没有处理过,则c的左孩子入栈。

    Ⅱ  如果条件Ⅰ不成立,且 c.right != null,且 h != c.right,则c的右孩子入栈。

    Ⅲ  如果Ⅰ和Ⅱ都不成立,说明c的左子树和右子树都打印完毕,则从栈中弹出c并打印,令h=c。

    3、重复步骤2直到栈为空。

        // h代表最近一次弹出并打印的节点,c代表stack的栈顶节点
        // 初试时h为头节点,c为null
        public void posOrderUnRecur2(TreeNode h) {
            if (h == null)
                return;
            Stack<TreeNode> s = new Stack<TreeNode>();
            s.push(h);
            TreeNode c = null;
            while (!s.isEmpty()) {
                c = s.peek();
                if (c.left != null && h != c.left && h != c.right)
                    s.push(c.left);
                else if (c.right != null && h != c.right)
                    s.push(c.right);
                else {
                    System.out.println(s.pop().val);
                    h = c;
                }
            }
        }

     

  • 相关阅读:
    【Networking】(转)一个非常好的epoll+线程池服务器Demo
    【算法】Logistic regression (逻辑回归) 概述
    【Linux】/dev/null 2>&1 详解
    单点登录与联合登录
    web项目报outmemory错误解决方案
    hadoop学习之HDFS
    ELK日志分析系统
    基于cookie共享的SSO中的遇到的问题
    oracle的隐式游标
    mysql截取字符串与reverse函数
  • 原文地址:https://www.cnblogs.com/wangkaipeng/p/9776778.html
Copyright © 2011-2022 走看看