遍历二叉树 概念小结

遍历二叉树:

二叉树由3个基本单元组成:根节点(D),左子树(L),右子树(R),若能依次遍历这三部分,便是遍历了整个二叉树。

根据先后顺序,便有6种方案: DLR   LDR   LRD   DRL   RDL   RLD .

若限定先左后右,则只有前三种情况,分别为:先(根)序遍历,中(根)序遍历,后(根)序遍历  。

先序遍历二叉树的操作定义为:

若二叉树为空,则空操作,否则

(1)访问根结点

(2)先序遍历左子树

(3)先序遍历右子树

中序遍历和后序遍历是类似的描述。

看一个例子:

二叉树为一种非线性结构,遍历二叉树是以一定规则将二叉树中结点排列成一个线性队列。

至于什么波兰式,什么是逆波兰式。只能求助于外界了。

https://blog.csdn.net/zhousanduo18/article/details/52458544

二叉树的中序和前序遍历序列可以唯一确定一棵二叉树 ,由前序和后序遍历则不能唯一确定一棵二叉树。

二叉树的中序和后序遍历序列可以唯一确定一棵二叉树,由前序和后序遍历则不能唯一确定一棵二叉树。

因为先序后序遍历都是确定根的位置,但不能确定左右子树的位置,一颗二叉树的建立需要根的位置也需要左右子树的位置。而中序遍历可以确认左右子树的位置。

通过先序遍历和中序遍历还原二叉树的例子 https://www.cnblogs.com/caijh/p/6935645.html

另一个例子 https://blog.csdn.net/cherry_chenrui/article/details/77871137

代码如下:


public class BuildTreePreOrderInOrder {

    /** 
     *              1 
     *             / \
     *            3   5 
     *           /     \
     *          7       11
     *       /  
     *      9       
     */  
    public static int treeNode = 0;//记录先序遍历节点的个数
    private List<Node> nodeList = new ArrayList<>();//层次遍历节点的队列
    
    //主函数
    public static void main(String[] args) {
        BuildTreePreOrderInOrder build = new BuildTreePreOrderInOrder();
        int[] preOrder = { 1, 3, 7, 9, 5, 11}; //先序遍历
        int[] inOrder = { 9, 7, 3, 1, 5, 11}; //中序遍历
        
        treeNode = preOrder.length;//初始化二叉树的节点数
        //根据先序遍历和中序遍历还原二叉树
        Node root = build.buildTreePreOrderInOrder(preOrder, 0, preOrder.length - 1, inOrder, 0, preOrder.length - 1);
        System.out.print("先序遍历:");
        build.preOrder(root);
        System.out.print("\n中序遍历:");
        build.inOrder(root);
        System.out.print("\n后序遍历:");
        build.postOrder(root);
        System.out.print("\n原二叉树:\n");
        build.prototypeTree(root);
    }

    /**
     * 分治法
     * 通过先序遍历结果和中序遍历结果还原二叉树
     * @param preOrder    先序遍历结果序列
     * @param preOrderBegin     先序遍历起始位置下标
     * @param preOrderEnd    先序遍历末尾位置下标
     * @param inOrder    中序遍历结果序列
     * @param inOrderBegin    中序遍历起始位置下标
     * @param inOrderEnd     中序遍历末尾位置下标
     * @return
     */
    public Node buildTreePreOrderInOrder(int[] preOrder, int preOrderBegin, int preOrderEnd, int[] inOrder, int inOrderBegin, int inOrderEnd) {
        if (preOrderBegin > preOrderEnd || inOrderBegin > inOrderEnd) {
            return null;
        }
        int rootData = preOrder[preOrderBegin];//先序遍历的第一个字符为当前序列根节点
        Node head = new Node(rootData);
        int divider = findIndexInArray(inOrder, rootData, inOrderBegin, inOrderEnd);//找打中序遍历结果集中根节点的位置
        int offSet = divider - inOrderBegin - 1;//计算左子树共有几个节点,节点数减一,为数组偏移量
        Node left = buildTreePreOrderInOrder(preOrder, preOrderBegin + 1, preOrderBegin + 1 + offSet, inOrder, inOrderBegin,inOrderBegin + offSet);
        Node right = buildTreePreOrderInOrder(preOrder, preOrderBegin + offSet + 2, preOrderEnd, inOrder, divider + 1, inOrderEnd);
        head.left = left;
        head.right = right;
        return head;
    }
    /**
     * 通过先序遍历找到的rootData根节点,在中序遍历结果中区分出:中左子树和右子树
     * @param inOrder    中序遍历的结果数组
     * @param rootData    根节点位置
     * @param begin    中序遍历结果数组起始位置下标
     * @param end    中序遍历结果数组末尾位置下标
     * @return return中序遍历结果数组中根节点的位置
     */
    public int findIndexInArray(int[] inOrder, int rootData, int begin, int end) {
        for (int i = begin; i <= end; i++) {
            if (inOrder[i] == rootData)
                return i;
        }
        return -1;
    }
    /**
     * 二叉树先序遍历结果
     * @param n
     */
    public void preOrder(Node n) {
        if (n != null) {
            System.out.print(n.val + ",");
            preOrder(n.left);
            preOrder(n.right);
        }
    }
    /**
     * 二叉树中序遍历结果
     * @param n
     */
    public void inOrder(Node n) {
        if (n != null) {
            inOrder(n.left);
            System.out.print(n.val + ",");
            inOrder(n.right);
        }
    }
    /**
     * 二叉树后序遍历结果
     * @param n
     */
    public void postOrder(Node n) {
        if (n != null) {
            inOrder(n.left);
            inOrder(n.right);
            System.out.print(n.val + ",");
        }
    }
    /**
     * 还原后的二叉树
     * 二叉数层次遍历
     * 基本思想:
     *     1.因为推导出来的二叉树是保存在Node类对象的子对象里面的,(类似于c语言的结构体)如果通过递归实现层次遍历的话,不容易实现
     *     2.这里采用List队列逐层保存Node对象节点的方式实现对二叉树的层次遍历输出
     *     3.如果父节点的位置为i,那么子节点的位置为,2i 和 2i+1;依据这个规律逐层遍历,通过保存的父节点,找到子节点。并保存,不断向下遍历保存。
     * @param tree
     */
    public void prototypeTree(Node tree){
        //用list存储层次遍历的节点
        if(tree !=null){
            if(tree!=null)
                nodeList.add(tree);
            nodeList.add(tree.left);
            nodeList.add(tree.right);
            int count=3;
            //从第三层开始
            for(int i=3;count<treeNode;i++){
                //第i层第一个子节点的父节点的位置下标
                int index = (int) Math.pow(2, i-1-1)-1;
                /**
                 * 二叉树的每一层节点数遍历
                 * 因为第i层的最大节点数为2的i-1次方个,
                 */
                for(int j=1;j<=Math.pow(2, i-1);){
                    //计算有效的节点的个数,和遍历序列的总数做比较,作为判断循环结束的标志
                    if(nodeList.get(index).left!=null)
                        count++;
                    if(nodeList.get(index).right!=null)
                        count++;
                    nodeList.add(nodeList.get(index).left);
                    nodeList.add(nodeList.get(index).right);
                    index++;
                    if(count>=treeNode)//当所有有效节点都遍历到了就结束遍历
                        break;
                    j+=2;//每次存储两个子节点,所以每次加2
                }
            }
            int flag=0,floor=1;
            for(Node node:nodeList){
                if(node!=null)
                    System.out.print(node.val+" ");
                else
                    System.out.print("# ");//#号表示空节点
                flag++;
                /**
                 * 逐层遍历输出二叉树
                 * 
                 */
                if(flag>=Math.pow(2, floor-1)){
                    flag=0;
                    floor++;
                    System.out.println();
                }
            }
        }
    }
    /**
     * 内部类
     * 1.每个Node类对象为一个节点,
     * 2.每个节点包含根节点,左子节点和右子节点
     */
    class Node {
        Node left;
        Node right;
        int val;
        public Node(int val) {
            this.val = val;
        }
    }
}

再看一看树与二叉树与森林之间的关系

当森林转换成二叉树时,其第一棵树的子树森林转换成左子树,其余树的森林转换成右子树。

至于二叉树的广度优先搜索和深度优先搜索请看一篇文章讲解  https://mp.weixin.qq.com/s/msj314u5U2v5477cgkzojg

猜你喜欢

转载自blog.csdn.net/qq_38261174/article/details/81278609