zoukankan      html  css  js  c++  java
  • 树 先序遍历 中序遍历 后序遍历

     写之前先看作用:

    先序遍历:在第一次遍历到节点时就执行操作,一般只是想遍历执行操作(或输出结果)可选用先序遍历;
    中序遍历:对于二分搜索树,中序遍历的操作顺序(或输出结果顺序)是符合从小到大(或从大到小)顺序的,故要遍历输出排序好的结果需要使用中序遍历
    后序遍历:后续遍历的特点是执行操作时,肯定已经遍历过该节点的左右子节点,故适用于要进行破坏性操作的情况,比如删除所有节点

    先序:中 左 右的顺序(先访问根节点,先序遍历左子树,先序遍历右子树

    中序:左 中 右的顺序

    后序:左 右 中的顺序

    遍历过程相同,只是访问各个节点的时机不同

    先序遍历

     递归实现:

        public static void preOrderRecur(TreeNode treeNode)
        {
            if (treeNode==null)
            {
                return;
            }
            System.out.println(treeNode.val);
            preOrderRecur(treeNode.left);
            preOrderRecur(treeNode.right);
        }

    够简单,需要注意终止条件。否则会空指针异常。

    非递归实现(自己维护一个栈):

    public static void preOrder(TreeNode treeNode)
        {
            if(treeNode==null)
            {
                return;
            }
            Stack<TreeNode> stack = new Stack<TreeNode>();//注意泛型
            stack.push(treeNode);
            while (stack.size()!=0)
            {
                treeNode=stack.pop();
                System.out.println(treeNode.val + " ");
                if(treeNode.right!=null)//注意不为null的条件,否则出栈会空指针
                {
                    stack.push(treeNode.right);//由于先处理左子树,后处理右子树,所以压栈顺序反过来就行
                }
                if(treeNode.left!=null)
                {
                    stack.push(treeNode.left);
                }
    
            }
        }

    这个迭代写的有点像递归了。。。

    中序遍历

    递归写法,真的爽,不用考虑具体的压栈过程,关注什么时候结束和递归逻辑就行

    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> list=new ArrayList<>();
            parse(root,list); 
            return list;       
        }
    
        public void parse(TreeNode root,List<Integer> list)
        {
            if(root==null)
            {
                return;
            }
            parse(root.left,list);
            list.add(root.val);
            parse(root.right,list);
        }
    }

    非递归写法:

    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            Stack<TreeNode> stack=new Stack<>();
            List<Integer> list=new ArrayList<>();
            while(stack.size()>0||root!=null)
            {
                while(root!=null)//处理root节点,去往最左侧,出循环后栈顶为优先级最高节点
                {
                    stack.push(root);
                    root=root.left;
                }
                TreeNode outNode=stack.pop();//到这里保证左侧已经没有东西了,outnode代表目前全树优先级最高的节点
                list.add(outNode.val);//处理“中”
                if(outNode.right!=null)//处理“右”,这一步加上去往最左能保证右子树被处理完
                {
                    root=outNode.right;
                }
            } 
            return list;
        }   
    }
    • root是要处理的节点,当root不为null时,还没有找到最高优先级的节点,当root为null时,最高优先级节点在栈顶,且这个最高优先级节点的父亲在栈的第二位
    • 处理最高优先级节点的办法是,弹出栈,输出最高优先级节点,处理右子树(即把root设置为其右孩子)
    • 还是有点绕的。。。

    后序遍历

    递归写法,差不多

    class Solution {
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> list=new ArrayList<>();
            postOrder(root,list);
            return list;
        }
    
        public void postOrder(TreeNode root,List<Integer> list)
        {
            if(root==null)
            {return;}
            postOrder(root.left,list);
            postOrder(root.right,list);
            list.add(root.val);
        }
    }

    非递归写法有两种

    第一种:双栈法,前序遍历不是中左右,改变一下压栈顺序就成了中右左,倒序过来就是左右中。

    倒序使用第二个栈就能实现,记录下来出栈的节点就可以

    class Solution {
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> list=new ArrayList<>();
            if(root==null)
            {return list;}
            Stack<TreeNode> stackReverse=new Stack<TreeNode>();
            Stack<TreeNode> stackResult=new Stack<TreeNode>();
            stackReverse.push(root);
            while(stackReverse.size()>0)
            {
                root=stackReverse.pop();
                stackResult.add(root);
                if(root.left!=null)
                {stackReverse.push(root.left);}
                if(root.right!=null)
                {stackReverse.push(root.right);}
            }
            while(stackResult.size()>0)
            {
                list.add(stackResult.pop().val);
            }
            return list;
        }
    }

     第二种,硬写呗

    和中序遍历有点像,先要找优先级最高的节点root,往左探

    当root为null时,cur=stack.pop,但是此时优先级更高的不是cur而是cur.right

    所以加入cur.right不为null,肯定要先处理右侧节点,cur要先放回栈

    为了到时右侧节点被处理完了,cur再出栈时能知道,所以加了一个pre(因为cur.right处理完肯定下一个就是cur)

    class Solution {
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> list=new ArrayList<>();
            if(root==null)
            {return list;}
            Stack<TreeNode> stack=new Stack<TreeNode>();
            TreeNode pre=null;
            while(stack.size()>0||root!=null)
            {
                while(root!=null)
                {
                    stack.push(root);
                    root=root.left;
                }
                TreeNode cur=stack.pop();
                if(cur.right==null||pre==cur.right)
                {
                    list.add(cur.val);
                    pre=cur;
                }
                else
                {
                    stack.push(cur);
                    root=cur.right;
                }
            }
            return list;
        }
    }
  • 相关阅读:
    使用Python学习RabbitMQ消息队列
    Python调用nmap扫描网段主机信息生成xml
    扫描网站服务器真实IP的小脚本
    C语言实现将彩色BMP位图转化为二值图
    Python socket编程之构造IP首部和ICMP首部
    ARP协议抓包之帧长度和Gratuitous ARP的问题
    合天解密200-找茬游戏
    合天misc100
    IDF实验室-简单的js解密
    IDF实验室—不难不易的js加密
  • 原文地址:https://www.cnblogs.com/take-it-easy/p/14081513.html
Copyright © 2011-2022 走看看