一看就会,二叉树的创建和三种遍历--前序、中序、后序(附java代码实现)

转载自原文

一、易懂的形象理解

其实从名字就可以很好的理解这三种遍历,我在第二点时候说,但是估计能翻到我的文的同学们之前肯定看过好多类似的了,那咱们换个思路~ 先用我想的一种简单易懂的形象思维理解一下前序、中序、后序 +层序!

1、先序遍历

先序遍历可以想象成,小人从树根开始绕着整棵树的外围转一圈,经过结点的顺序就是先序遍历的顺序
先序遍历结果:ABDHIEJCFKG
在这里插入图片描述
让我们来看下动画,和小人儿一起跑两遍就记住啦,记住是绕着外围跑哦
在这里插入图片描述
在这里插入图片描述

2、中序遍历

中序遍历可以想象成,按树画好的左右位置投影下来就可以了
中序遍历结果:HDIBEJAFKCG
中序遍历
下面看下投影的过程动画,其实就是按左右顺序写下来就行了
在这里插入图片描述

3、后序遍历

后序遍历就像是剪葡萄,我们要把一串葡萄剪成一颗一颗的。
还记得我们先序遍历绕圈的路线么?
就是围着树的外围绕一圈,如果发现一剪刀就能剪下的葡萄(必须是一颗葡萄),就把它剪下来,组成的就是后序遍历了。
后序遍历结果:HIDJEBKFGCA
在这里插入图片描述
让我们来看下动画
在这里插入图片描述

4、层序遍历

层序遍历太简单了,就是按照一层一层的顺序,从左到右写下来就行了。
后序遍历结果:ABCDEFGHIJK
在这里插入图片描述

不知道通过这种方式,有没有觉得闭着眼睛都能写出前序、中序、后序 、层序了呀,不过这只是为了大家好理解,我想出的一种形象思维,为了用代码实现,我们还需要具体了解一下前序、中序、后序遍历。

二、真正理解三种遍历

来,让我们先把所有空结点都补上。
还记得我们先序和后序遍历时候跑的顺序么?按照这个顺序再跑一次,就是围着树的外围跑一整圈
让我们来理解一下绕着外围跑一整圈的真正含义是:遍历所有结点时,都先往左孩子走,再往右孩子走。
在这里插入图片描述
观察一下,你有什么发现?
有没有发现,除了根结点和空结点,其他所有结点都有三个箭头指向它。
一个是从它的父节点指向它,一个是从它的左孩子指向它,一个是从它的右孩子指向它
一个结点有三个箭头指向它,说明每个结点都被经过了三遍。一遍是从它的父节点来的时候,一遍是从它的左孩子返回时,一遍是从它的右孩子返回时

其实我们在用递归算法实现二叉树的遍历的时候,不管是先序中序还是后序,程序都是按照上面那个顺序跑遍所有结点的
先序中序和后序唯一的不同就是,在经过结点的三次中,哪次访问(输出或者打印或者做其他操作)了这个结点。有点像大禹治水三过家门,他会选择一次进去。
先序遍历顾名思义,就是在第一次经过这个结点的时候访问了它。就是从父节点来的这个箭头的时候,访问了它。
中序遍历也和名字一样,就是在第二次经过这个结点的时候访问了它。就是从左孩子返回的这个箭头的时候,访问了它。
后序遍历,就是在第三次经过这个结点的时候访问了它。就是从右孩子返回的这个箭头的时候,访问了它。

怎么样,这样有没有很好的理解?其实不管是前序中序还是后序,在程序里跑的时候都是按照同样的顺序跑的,每个结点经过三遍,第几遍访问这个结点了,就叫什么序遍历。
当我们脑子里有这个概念的时候, 再去看实现代码就很好理解了,下一篇博文我会贴出和讲解具体的实现代码。

三、代码实现

需求:把一个数组生成一个二叉树,并打印前序、中序、后序的结果。
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
这个数组生成的二叉树如下:
在这里插入图片描述
创建个java文件叫:TreeNode.java,内容如下,可直接复制使用

public class TreeNode {
    private int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    private static List<Node> nodeList = null;

    //内部类 结点
    private static class Node {
        Node leftChild;
        Node rightChild;
        int data;

        //构造方法初始化
        Node(int newData) {
            leftChild = null;
            rightChild = null;
            data = newData;
        }
    }

    public void createBinTree() {
        if (array.length > 0) {
            nodeList = new LinkedList<Node>();
            // 将一个数组的值依次转换为Node节点
            for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) {
                nodeList.add(new Node(array[nodeIndex]));
            }
            // 对前lastParentIndex-1个父节点按照父节点与孩子节点的数学关系建立二叉树
            for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) {
                // 左孩子
                nodeList.get(parentIndex).leftChild = nodeList.get(parentIndex * 2 + 1);
                // 右孩子
                nodeList.get(parentIndex).rightChild = nodeList.get(parentIndex * 2 + 2);
            }
            // 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理
            int lastParentIndex = array.length / 2 - 1;
            // 最后一个节点的左孩子
            if (array.length != 1) {
                nodeList.get(lastParentIndex).leftChild = nodeList.get(lastParentIndex * 2 + 1);
            }
            // 最后一个节点的右孩子,如果数组的长度为奇数并且不止一个节点才建立右孩子
            if (array.length != 1 && array.length % 2 == 1) {
                nodeList.get(lastParentIndex).rightChild = nodeList.get(lastParentIndex * 2 + 2);
            }

        }
    }

    /**
     * 先序遍历
     */
    public static void preOrderTraverse(Node node) {
        if (node == null)
            return;
        System.out.print(node.data + " ");
        preOrderTraverse(node.leftChild);
        preOrderTraverse(node.rightChild);
    }

    /**
     * 中序遍历
     */
    public static void inOrderTraverse(Node node) {
        if (node == null)
            return;
        inOrderTraverse(node.leftChild);
        System.out.print(node.data + " ");
        inOrderTraverse(node.rightChild);
    }

    /**
     * 后序遍历
     */
    public static void postOrderTraverse(Node node) {
        if (node == null)
            return;
        postOrderTraverse(node.leftChild);
        postOrderTraverse(node.rightChild);
        System.out.print(node.data + " ");
    }

    public static void main(String[] args) {
        TreeNode binTree = new TreeNode();
        binTree.createBinTree();
        // nodeList中第0个索引处的值即为根节点
        Node root = nodeList.get(0);
        System.out.println("先序遍历:");
        preOrderTraverse(root);
        System.out.println();
        System.out.println("中序遍历:");
        inOrderTraverse(root);
        System.out.println();
        System.out.println("后序遍历:");
        postOrderTraverse(root);
    }
}

运行结果:

先序遍历:
1 2 4 8 9 5 3 6 7 
中序遍历:
8 4 9 2 5 1 6 3 7 
后序遍历:
8 9 4 5 2 6 7 3 1 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值