二叉树前序、中序、后序遍历,递归和非递归思路详解

概念理解

二叉树所谓的前序遍历、中序遍历、后序遍历中,前中后的意思,其实指的是根节点相比较于他的左右孩子节点,何时打印的意思。比如前序遍历的意思,指的就是根节点相较于他的左右孩子先打印,然后再打印其左右孩子,这就是根节点优先,所以叫先序遍历。中序遍历,根节点在打印完左孩子后,在中间打印,所以叫做中序遍历。后序遍历,是先打印完左右孩子,再打印中间根节点,因此是后续遍历。

递归方式的前中后序遍历

递归方式是最容易实现二叉树的前中后序遍历的,因为递归方式的代码,能非常直观的体现出二叉树三种遍历方式的特点。
前序遍历
代码中可以清晰看到,先打印根节点,再递归其左孩子,然后是右孩子。打印根节点在最前面。

    //递归前序遍历
    public static void preOrderRecur(TreeNode head){
        if(head==null){
            return;
        }
        System.out.println(head.value);
        preOrderRecur(head.left);
        preOrderRecur(head.right);
 }

中序遍历
代码中可以清晰看到,先递归左孩子,再打印根节点,然后是右孩子。打印根节点在中间。

    //递归中序遍历
    public static void inOrderRecur(TreeNode head){
        if(head==null){
            return;
        }
        inOrderRecur(head.left);
        System.out.println(head.value);
        inOrderRecur(head.right);
    }

后序遍历
先递归左右孩子,再打印根节点,打印根节点在最后。

    //递归后序遍历
    public static void afterOrderRecur(TreeNode head){
        if(head==null){
            return;
        }
        afterOrderRecur(head.left);
        afterOrderRecur(head.right);
        System.out.println(head.value);
    }

非递归实现前中后序遍历

观察二叉树的结构,可以发现,为什么二叉树的遍历要用递归实现呢?也就是在问,为什么二叉树的遍历要用栈来实现?那是因为,二叉树的结构,只有从父节点到孩子节点的路径,却没有孩子节点到父节点的路径,一旦从父节点遍历到孩子节点,就无法返回了,那么,如果想返回,就需要一种能将从上到下的结构逆序的数据结构,那么特征就很明显了,栈就是能将数据顺序逆序过来的过程,而递归本质就是栈,因此,二叉树的遍历用递归是最容易实现的。
递归的实质,其实就是系统帮我们实现栈的结构,来保存数据。只不过,系统的栈很复杂,压栈时会保存所有状态。其实,递归时,每个节点要回溯三次的,而这些,系统栈都帮我们做好了。那么,如果我们想要实现非递归的遍历,其实就是想办法不用系统栈,自己实现栈的过程。而我们自己实现的栈,其实只需要保存有用的数据就行了。

非递归前序遍历
前序遍历,其实就是实现:中、左、右。他自己吃饱喝足了,才能轮到他孩子。每当拿到一个节点,先打印,然后将其右节点先入栈,再入栈左节点,然后再出栈,就能实现中、左、右的顺序。

    //非递归前序遍历
    public static void preOrderUnRecur(TreeNode head){
        if(head==null){
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(head);
        while (!stack.isEmpty()){
            head=stack.pop();
            System.out.println(head.value);
            if(head.right!=null){
                stack.push(head.right);
            }
            if(head.left!=null){
                stack.push(head.left);
            }
        }
    }

非递归中序遍历
中序遍历就是实现左、中、右。就是无限宠溺左孩子,左孩子再宠溺左孩子,右孩子后娘养的,排最后。
当我们拿到一个节点,不能先打印,因为要先打印他的左孩子,那就先将他压入栈中,然后来到他的左孩子,如果他的左孩子还有左孙子,那他的左孩子又不能先打印了,只能先压入栈,打印他的左孙子,依次往复。当某个节点左孩子为空,或者左孩子打印好了,就返回他自己,然后打印,最后才去他的右孩子。

    //非递归中序遍历
    public static void inOrderUnRecur(TreeNode head){
        if(head==null){
            return;
        }
        Stack<TreeNode> stack=new Stack<>();
        while (!stack.isEmpty()||head!=null){
            if(head!=null){
                stack.push(head);
                head=head.left;
            }else {
                head=stack.pop();
                System.out.println(head.value);
                head=head.right;
            }
        }
    }

非递归实现后续遍历
非递归实现后续遍历最简答的方法就是依次入队列。当然,这里的话,既然是递归改非递归,底层原理还是用栈来改非递归。
先考虑这样一个问题,前面非递归前序遍历中,根节点打印后,先入栈右孩子,再入栈左孩子,就能实现中左右的顺序,那么,实现中右左呢?那不就改个顺序的事情吗?打印根节点,先入栈左孩子,再入栈右孩子,然后出栈,就是中右左。
有了中右左,那么,后序遍历是什么顺序呢?左右中对吧?发现了什么?后序遍历其实就是中左右倒过来了。倒序结构,想到了什么?没错,多一个栈就能轻松实现了。

    //非递归后序遍历
    public static void aftOrderUnRecur(TreeNode head){
        if(head==null){
            return;
        }
        Stack<TreeNode> s1=new Stack<>();
        Stack<TreeNode> s2=new Stack<>();
        s1.push(head);
        while (!s1.isEmpty()){
            head=s1.pop();
            s2.push(head);
            if(head.left!=null){
                s1.push(head.left);
            }
            if(head.right!=null){
                s1.push(head.right);
            }
        }
        while (!s2.isEmpty()){
            System.out.println(s2.pop().value);
        }
    }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值