• 二叉树基础之前序遍历、中序遍历、后序遍历的递归和非递归实现


    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6604347.html 

    一:树的结点

        一般默认树的结点由:结点值、左儿子、右儿子,构造函数组成。

    class TreeNode{
        int value;
        TreeNode  left;
        TreeNode  right;
        public TreeNode(int i){
        this.value=i;
        }
    }

    二:二叉树的遍历实现——递归和非递归

        1:递归实现==按照遍历方式(前、中、后)对左、根、右的访问顺序去 打印结点值、递归左儿子、递归右儿子

        public void preorder(TreeNode root){
            if(root==null){
                return;
            }
            System.out.println(root.val);    //
            preorder(root.left,pre);//
            preorder(root.right,pre);//
        }
    
        public void inorder(TreeNode root){
            if(root==null){
                return;
            }
            inorder(root.left,in); /左
            System.out.println(root.val);//
            inorder(root.right,in);//
        }
    
        public void postorder(TreeNode root){
            if(root==null){
                return;
            }
            postorder(root.left,post);//
            postorder(root.right,post);//
            System.out.println(root.val);//
        }

        2:非递归实现==使用 栈 来控制结点的处理顺序

        前序遍历==利用栈的倒序输出特性,每次弹出当前结点时按“先右后左”的顺序把当前结点的儿子结点入栈

     public void preorder(TreeNode root,ArrayList<Integer> pre){
            if(root==null){
                return;
            }
            Stack node=new Stack<TreeNode>();
            TreeNode curr=null;
            node.push(root);
            while(!node.isEmpty()){
                //处理根结点
                curr=node.pop();
                pre.add(curr.val);
                //先把右儿子入栈
                if(root.right!=null){
                    node.push(root.right);
                }
                //后把左儿子入栈,下一循环时就是左儿子先处理
                if(root.left!=null){
                    node.push(root.left);
                }
            }
        }

        中序遍历==curr指向根,把根入栈:令curr指向左儿子,如果非空则入栈,重复这步;//循环遍历左子树

                                                      如果curr为空,则弹出栈顶元素;//处理子树的根

                                                      令curr指向弹出元素的右儿子,如果非空则入栈;//处理右儿子。然后回到第一步时处理右儿子的左子树

                                                      重复以上三步直到栈为空。

        public void inorder(TreeNode root,ArrayList<Integer> in){
            if(root==null){
                return;
            }
            Stack<TreeNode> node=new Stack<TreeNode>();
            TreeNode curr=root;
    //先把根入栈 node.push(root);
    while(!node.isEmpty()){ //循环处理左子树,让左子树入栈 while(curr!=null){ curr=curr.left; if(curr!=null){ node.push(curr); } } //左子树入栈完毕,开始处理栈中结点。由于是 按照 根—左 的顺序入栈的,所以处理的时候是 左——根 curr=(TreeNode)node.pop(); in.add(curr.val); //元素弹出时说明前面的它的左子树已经处理完了,并且元素自身作为根也处理了。此时看这个根有没有右儿子,有则入栈处理 右。回到第一步,右子树的处理同样是:左、根、右 curr=curr.right; if(curr!=null){ node.push(curr); } } }

        

        后序遍历==使用两个栈,root入栈1:S1弹出栈顶,curr指向S1弹出的元素,把curr入S2,同时令curr的左右儿子依次入S1;

                                                        重复上面,直到S1为空时,树遍历完毕,依次弹出S2则为后序遍历。

                        由于栈1结点的儿子是按照“左右”顺序入栈的,所以出栈再入栈2时就是按照“根右左”的顺序,所以栈2弹出时就是“左右根”后序遍历了。

        public void postorder(TreeNode root,ArrayList<Integer> post){
            if(root==null){
                return;
            }
            Stack<TreeNode> s1=new Stack<TreeNode>();
            Stack<TreeNode> s2=new Stack<TreeNode>();
            s1.push(root);
            TreeNode curr=null;
    //S1弹出栈顶,curr指向S1弹出的元素,把curr入S2,同时令curr的左右儿子依次入S1
    while(!s1.isEmpty()){ curr=(TreeNode)s1.pop(); s2.push(curr); if(curr.left!=null){ s1.push(curr.left); } if(curr.right!=null){ s1.push(curr.right); } }
    //依次弹出S2则为后序遍历
    while(!s2.isEmpty()){ curr=(TreeNode)s2.pop(); post.add(curr.val); }
  • 相关阅读:
    USDT与omniCore钱包
    C# 事件(第四章)
    委托进阶(第三章)
    委托入门(第二章)
    委托入门(第一章)
    asp.net页面生命周期
    在WEB程序中小心使用"ThreadStatic"
    如何在一个请求中共享数据或对象实例
    .net垃圾回收机制原理
    MVC模式简介
  • 原文地址:https://www.cnblogs.com/ygj0930/p/6604347.html
Copyright © 2020-2023  润新知