zoukankan      html  css  js  c++  java
  • 二叉树的先序、中序以及后序遍历(递归 && 非递归)

    树节点定义:

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

    递归建立二叉树:

        //递归建立二叉树
        public static void BuildTree(TreeNode node, int data){
            if(node == null){
                node = new TreeNode(data);
            }
            
            if(data <= node.val){
                if(node.left == null){
                    node.left = new TreeNode(data);
                }else{
                    BuildTree(node.left, data);
                }
            }
            
            if(data > node.val){
                if(node.right == null){
                    node.right = new TreeNode(data);
                }else{
                    BuildTree(node.right, data);
                }
            }    
        }

    1、先序遍历

    遍历方式:根节点-->左节点-->右节点

    递归先序遍历:

        //先序递归遍历二叉树
        public static List<Integer> preTravese(TreeNode root,List<Integer> arr){
            if(root == null)
                return arr;
            if(root != null){
                arr.add(root.val);
                arr = preTravese(root.left,arr);
                arr = preTravese(root.right,arr);
            }
            return arr;
        }

    非递归遍历:

    对于任意一个结点p

    1)访问结点p,并将p入栈

    2)将p变为p的左孩子结点,如果p的不为空,循环至 1); 否则弹出当前栈顶使用p接收,将p变为p的右孩子结点;

    3)当p结点为null并且栈为空时,结束循环。

    代码:

        //非递归先序遍历
        public static List<Integer> preorderTraversal(TreeNode root){
            List<Integer> arr = new ArrayList<Integer>();
            if(root == null){
                return arr;
            }
            Stack<TreeNode> ts = new Stack<TreeNode>();
            TreeNode ptr = root;
            while( ptr != null || !ts.isEmpty()){
                while(ptr != null){
                    arr.add(ptr.val);
                    ts.push(ptr);
                    ptr = ptr.left;
                }
                if( !ts.isEmpty()){
                    ptr = ts.pop();
                    ptr = ptr.right;
                }
            }
            return arr;
        }

    2、中序遍历

    遍历方式: 左子树-->根节点-->右子树

    递归中序遍历:

        //中序递归遍历二叉树
        public static List<Integer> inTravese(TreeNode root,List<Integer> arr){
            if(root == null)
                return arr;
            if(root != null){
                arr = inTravese(root.left,arr);
                arr.add(root.val);
                arr = inTravese(root.right,arr);
            }
            return arr;
        }

    非递归中序遍历:

    对于任意一个结点p

    1)当结点不为null,将结点压栈;

    2)将p更新为它的左孩子,如果左孩子不为空,循环至 1);否则弹出栈顶元素赋值给p,访问p结点,p更新为p的右孩子;

    3)当p为null 并且栈为空时结束循环。

    代码:

        //中序非递归遍历
        public static List<Integer> inorderTraversal(TreeNode root){
            List<Integer> arr = new ArrayList<Integer>();
            if(root == null){
                return arr;
            }
            Stack<TreeNode> ts = new Stack<TreeNode>();
            TreeNode ptr = root;
            while( ptr != null || !ts.isEmpty() ){
                while(ptr != null){
                    ts.push(ptr);
                    ptr = ptr.left;
                }
                if(!ts.isEmpty()){
                    ptr = ts.pop();
                    arr.add(ptr.val);
                    ptr = ptr.right;
                }
            }
            return arr;
        }

    3、后序遍历

    遍历方式:左子树-->右子树-->根节点

    递归遍历:

        //后序递归遍历二叉树
        public static List<Integer> lastTravese(TreeNode root,List<Integer> arr){
            if(root == null)
                return arr;
            if(root != null){
                arr = lastTravese(root.left,arr);
                arr = lastTravese(root.right,arr);
                arr.add(root.val);
            }
            return arr;
        }

    非递归遍历:

    对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因为其右孩子还没有被访问。

    接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。

    这样就可以保证正确的访问顺序。

    可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。

    代码:

    首先新建一个类来记录结点是否是第一次弹栈:

    //新建一个类,用来记录该结点是不是第一次弹栈
    class NewTreeNode{
        TreeNode ptr;
        boolean isFirst;
        public NewTreeNode(TreeNode ptr){
            this.ptr = ptr;
            this.isFirst = true;
        }
    }

    非递归后序遍历二叉树:

        //后序非递归遍历二叉树
        public static List<Integer> lastTraverse(TreeNode root){
            List<Integer> arr = new ArrayList<Integer>();
            if(root == null){
                return arr;
            }
            Stack<NewTreeNode> nts = new Stack<NewTreeNode>();
            NewTreeNode nptr = null;
            TreeNode ptr = root;
            while( ptr!= null || !nts.isEmpty()){
                while(ptr != null){
                    nptr = new NewTreeNode(ptr);
                    nts.push(nptr);
                    ptr = ptr.left;
                }
                
                if(!nts.isEmpty()){
                    nptr = nts.pop();
                    if(nptr.isFirst){
                        nptr.isFirst = false;
                        nts.push(nptr);
                        ptr = nptr.ptr.right;
                    }else{
                        arr.add(nptr.ptr.val);
                        //ptr置为null,因为此时它的左右子树都已经访问完毕
                        ptr = null;
                    }
                }
            }
            return arr;
        }
    
    }
  • 相关阅读:
    科学计算——笔记
    Python_scrapyRedis零散
    Python博文_爬虫工程师是干什么的
    [单选题]怎样打开或创建一个文件?
    [问答题] 写出一个正则表达式,过虑网页上的所有JS/VBS脚本(即把script标记及其内容都去掉):
    [单选题]<?php$age =18;$age?$age+10:$age+20;echo $age;?>
    [单选题]有关PHP面向对象的说法,不对的是:
    [单选题]要循环操作非顺序索引的数组时,可以用下面哪个函数来读取数组当面元素的索引值?
    [单选题]PHP中定义常量的方法是:
    [单选题]stdClass的一个对象如何设置成员value的值?
  • 原文地址:https://www.cnblogs.com/bywallance/p/5553946.html
Copyright © 2011-2022 走看看