java数据结构与算法总结(十三)--二叉树(遍历方法、递归实现)

二叉树的遍历


二叉树的遍历是指按照某种顺序访问二叉树中的每个结点,使每个结点被访问一次且仅被访问一次。通过一次完整的遍历,可使二叉树中的结点信息由非线性排列变成某种意义上的线性序列。也就是说,遍历操作是非线性结构线性化。

由二叉树的定义可知,一棵二叉树由根结点、左子树和右子树三部分组成。因此,只需要依次遍历这三个部分,就可以遍历整个二叉树。若以D、L、R分别表示访问根结点、遍历根结点的左子树和遍历根结点的右子树,则二叉树的遍历方式有6种,它们的含义如下表所示:

 先左后右先右后左
先序遍历DLRDRL
中序遍历LDRRDL
后序遍历LRDRLD


如果限定先左后右,则只有前三种方式。但这只是由根结点到左右子树结点的方式来遍历,其实还有一种遍历方式,层次遍历。下面就来讨论这四种遍历方式。

二叉树的遍历方式


先序遍历


先序遍历的递归过程为:若二叉树为空,遍历结束;否则,访问根结点,先序遍历根结点的左子树,先序遍历根结点的右子树

对于上图的先序遍历,先遍历根结点A,再遍历A的左子树。而要遍历A的左子树,先遍历A的左子树的根结点B,再遍历它的左子树。如此循环。最终得到的结点序列:ABDGHCEIF。

    public void preorder(Node<E> p) {
        if (isEmpty()) {
            System.out.println("Tree is empty");
            return;
        }
        if (p != null) {
            System.out.print(p.getData() + " ");
            preorder(p.getLchild());
            preorder(p.getRchild());
        }
    }


中序遍历


中序遍历的递归过程为:若二叉树为空,遍历结束;否则,中序遍历根结点的左子树,访问根结点,中序遍历根结点的右子树。

对于上图的中序遍历,要遍历A根点,先遍历它的左子树。要遍历A的左子树,就要遍历它左子树的左子树。也就是说,最开始遍历的是最左边的结点G。然后遍历根结点,再右子树。如此循环。最终得到的结点序列:GDHBAEICF。

    public void inorder(Node<E> p) {
        if (isEmpty()) {
            System.out.println("Tree is empty");
            return;
        }
        if (p != null) {
            inorder(p.getLchild());
            System.out.print(p.getData() + " ");
            inorder(p.getRchild());
        }
    }


后序遍历


后序遍历的递归过程为:若二叉树为空,遍历结束;否则,后序遍历根结点的左子树,后序遍历根结点的右子树,访问根结点。

对于上图的后序遍历,要遍历A根点,先遍历它的左子树。要遍历A的左子树,就要遍历它左子树的左子树。也就是说,最开始遍历的是还是最左边的结点G。然后遍历右子树,再根结点。如此循环。最终得到的结点序列:GHDBIEFCA。

    

public void postorder(Node<E> p) {
        if (isEmpty()) {
            System.out.println("Tree is empty");
            return;
        }
        if (p != null) {
            postorder(p.getLchild());
            postorder(p.getRchild());
            System.out.print(p.getData() + " ");
        }
    }


层次遍历


所谓层次遍历,就是从二叉树的第一层(根结点)开始,从上至下逐层遍历,在同一层,则按照从左至右的顺序对每个结点逐个访问。

层次遍历的基本思想是:由于层次遍历结点的顺序是先遇到的结点先访问,与队列的操作顺序相同。所以,在进行层次遍历时,设置一个队列,将根结点引用入队,当队列非空时,循环执行以下三步:

  1. 从队列中取出一个结点的引用,并访问该节点;
  2. 若该结点的左子树非空,将该结点的左子树引用入队;
  3. 若该结点的右子树非空,将该结点的右子树引用入队。
public void levelOrder(Node<E> root) {
        // 根结点为空
        if (root == null) {
            return;
        }
        // 设置一个队列保存层序遍历的结点
        Queue<Node<E>> q = new LinkedList<Node<E>>();
        // 根结点入队
        q.add(root);
        // 队列非空,结点没有处理完
        while (!q.isEmpty()) {
            // 结点出队
            Node<E> tmp = q.poll();
            // 处理当前结点
            System.out.print(tmp.getData() + " ");
            // 将当前结点的左孩子结点入队
            if (tmp.getLchild() != null) {
                q.add(tmp.getLchild());
            }
            if (tmp.getRchild() != null) {
                // 将当前结点的右孩子结点入队
                q.add(tmp.getRchild());
            }
        }
    }


总结与分析


二叉树的四种遍历方式,先序遍历、中序遍历、后序遍历、层次遍历,除了层次遍历使用队列的方式之外,其他三种都是采用的递归的方式实现的,而递归是可以用栈的方式来实现的。也就是说二叉树的递归方式说到底也就是栈和队列的两种实现方式。这和图的遍历方式(深度优先、广度优先)的思想是一致的。
————————————————
版权声明:本文为CSDN博主「Yngz_Miao」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38410730/article/details/79587728

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值