树的前序,中序,后序遍历。

定义与解释

前序遍历:

前序遍历(VLR), [1] 是二叉树遍历的一种,也叫做先根遍历、先序遍历、前序周游,可记做根左右。前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。

中序遍历:

中序遍历(LDR)是二叉树遍历的一种,也叫做中根遍历、中序周游。在二叉树中,中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。

后序遍历:

后序遍历(LRD)是二叉树遍历的一种,也叫做后根遍历、后序周游,可记做左右根。后序遍历有递归算法和非递归算法两种。在二叉树中,先左后右再根,即首先遍历左子树,然后遍历右子树,最后访问根结点。

这里我们使用一个 二叉搜索树 来解释这三种遍历。
在这里插入图片描述

首先怎么来看这个图呢?

1.图中1一个圆圈代表一个树节点,里面的数组代表值。

2.图中红色的箭头线,代表遍历时的路径,编号代表先后顺序,从1开始一直往后。

3.实际叶子节点下面也可以看做有两个null的子节点,这里只画了叶子节点2下面的null子节点,其他叶子节点4,6,8也是一样可以看成有的。每次要走到null才会返回。

4.图中每一个节点都有4个红色箭头线连接,我们可以将最左边的看成第一次经过该节点,下面两条看成第二次经过该节点,最右边的看成第三次经过该节点。所以每个非null节点,会被经过3次。

5.为方便表示,使用线1表示红色箭头线1,点5表示节点5 。

前序遍历:
从根节点进来,第一次经过点5,打印5
线1,第一次经过点3,打印3;
线2,第一次经过点2,打印2;
线3,遇到null,往回走;
线4,第二次经过点2;
线5,遇到null,往回走;
线6,第三次经过点2;
线7,第二次经过点3;
线8,第一次经过点4,打印4;
。。。

最终结果为:5,3,2,4,7,6,8
总结:第一次经过非null节点,就打印该节点。

中序遍历:
从根节点进来,第一次经过点5;
线1,第一次经过点3;
线2,第一次经过点2;
线3,遇到null,往回走;
线4,第二次经过点2,打印2;
线5,遇到null,往回走;
线6,第三次经过点2;
线7,第二次经过点3,打印3;
线8,第一次经过点4;
。。。

最终结果为:2,3,4,5,6,7,8
总结:第二次经过非null节点,就打印该节点。

后序遍历:
从根节点进来,第一次经过点5;
线1,第一次经过点3;
线2,第一次经过点2;
线3,遇到null,往回走;
线4,第二次经过点2;
线5,遇到null,往回走;
线6,第三次经过点2,打印2;
线7,第二次经过点3;
线8,第一次经过点4;
。。。

最终结果为:2,4,3,6,8,7,5
总结:第三次经过非null节点,就打印该节点。

递归代码实现

使用Java,jdk1.8 。三种遍历用递归实现都非常简单。

//    前序遍历
    private void DLR(BSTNode<T> node){
        if(node==null){
            return;
        }
        System.out.println(node.val);
        DLR(node.leftNode);
        DLR(node.rightNode);
    }
    public void DLR(){
        DLR(root);
    }

//    中序遍历
    private void LDR(BSTNode<T> node){
        if(node==null){
            return;
        }
        LDR(node.leftNode);
        System.out.println(node.val);
        LDR(node.rightNode);
    }
    public void LDR(){
        LDR(root);
    }

//    后续遍历
    private void LRD(BSTNode<T> node){
        if(node==null){
            return;
        }
        LRD(node.leftNode);
        LRD(node.rightNode);
        System.out.println(node.val);
    }
    public void LRD(){
        LRD(root);
    }

非递归代码实现

使用Java,jdk1.8 。用循环实现会比递归要复杂些,需要借助一个栈。

前序遍历:
(1)第一次经过节点,然后将其入栈,并且先不去往下经过其子节点。(从根节点进来,第一次经过点5;)
(2)从栈顶弹出打印,此时的节点,其子节点都还没有被经过,相当于其只被经过过一次。
(3)先将其右子节点入栈,再将其左子节点入栈,此时相当于第一次经过了其子节点。(线11,第一次经过点7;线1,第一次经过点3;)

//    1.先把根节点入栈
//    循环(栈不为空){
//        2.弹出节点打印
//        3.把右子节点入栈
//        4.把左子节点入栈
//    }
//    实际上,第一次入栈时,栈顶节点的两个子节点都还没有走过,就相当于经过1次,然后弹出打印。
    public void DLR2(){
        Stack<BSTNode<T>> stack = new Stack<>();
        stack.push(root);
        while (!stack.empty()){
            BSTNode<T> node = stack.pop();
            System.out.println(node.val);
            if(node.rightNode!=null)stack.push(node.rightNode);
            if(node.leftNode!=null)stack.push(node.leftNode);
        }
    }

中序遍历:
(1)第一次经过节点,入栈,然后继续往下经过其左子节点,再入栈,一直持续到遇见null,线路往回走。(从根节点进来,第一次经过点5;线1->线2->线3->线4;)
(2)从栈顶弹出打印,此时的节点,其左子节点已经被经过,前面已经是经过了其左子节点null,然后线路往回走了,所以此时的节点已经被经过了第二次。
(3)先将其右子节点入栈,然后从右子节点开始,一直经过左子节点,并将它们入栈。(线5,不过此时为null,不会入栈;)

//    1.先从根节点开始,一路把左子节点入栈
//    循环(栈不为空){
//      2.弹出节点打印
//      3.将当前节点的右子节点中的左节点一路入栈
//    }
//    实际上,第一次入栈时,就已经把栈顶节点的左子节点走过一次,然后弹出栈时,相当于是第2次经过,然后弹出打印。
    public void LDR2(){
        Stack<BSTNode<T>> stack = new Stack<>();
        BSTNode<T> node = root;
        while (node!=null){
            stack.push(node);
            node = node.leftNode;
        }
        while (!stack.empty()){
            node = stack.pop();
            System.out.println(node.val);
            node = node.rightNode;
            while (node!=null){
                stack.push(node);
                node = node.leftNode;
            }
        }
    }

后序遍历:
(1)第一次经过节点,入栈,然后继续往下经过左子节点,如果没有左子节点,就去经过右子节点。一直到左右子节点都为null。(从根节点进来,第一次经过点5;线1->线2->线3->线4->线5->线6;)
(2)从栈顶弹出打印,此时的节点,其左子节点和右子节点都已经被经过,所以此时的节点是第三次被经过了。
(3)先获取当前节点的父节点,在将父节点的右子节点入栈,然后从右子节点开始,一直经过左子节点,并将它们入栈,如果没有左子节点,就经过右子节点。(线7->线8;)

//    1.先从根节点开始,一路把左子节点入栈,如果左子节点没有,就挑右子节点
//    循环(栈不为空){
//      2.弹出节点打印
//      3.如果当前节点是其父节点的左子节点,
//          则从其父节点的右子节点开始,一路把左子节点入栈,如果左子节点没有,就挑右子节点
//    }
//    实际上,第一次入栈时,就已经把栈顶节点的两个子节点都走过一次了,所以弹出栈时,是第3次经过,然后弹出打印。
    public void LRD2(){
        Stack<BSTNode<T>> stack = new Stack<>();
        BSTNode<T> node = root;
        while (node!=null){
            stack.push(node);
            if(node.leftNode!=null)node=node.leftNode;
            else node=node.rightNode;
        }
        while (!stack.empty()){
            node = stack.pop();
            System.out.println(node.val);
            if(!stack.empty()&&stack.peek().leftNode==node){
                node = stack.peek().rightNode;
                while (node!=null){
                    stack.push(node);
                    if(node.leftNode!=null)node=node.leftNode;
                    else node=node.rightNode;
                }
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值