zoukankan      html  css  js  c++  java
  • 树-二叉树存储及遍历

    一、二叉树的概述

    二、树和二叉树的区别

      1、普通树中节点的最大度数没有限制,而二叉树节点的最大度数是2。

      2、无序树的节点无左右之分,而二叉树的节点有左右之分,也就是二叉树的是有序树

    三、满二叉树

      如果它包含了2的整指数节点,就是满二叉树,满二叉树的特点是每一层上的节点数都是最大节点数,即各层节点数分别为1、2、4、8、16...2的k-1次方

     四、完全二叉树

      如果一棵二叉树除最后一层外,就其余层的所有节点都是满的,并且最后一层或者是满的,或者仅仅在右边缺少若干连续的节点,这就是完全二叉树。

     五、二叉树的性质

      1、二叉树第i层上的节点数目至多为2的i-1次方。

      2、深度为k的二叉树总共的节点数为:至多有2的k次方-1个节点

      3、在任何一棵二叉树中,如果其叶子节点的数量为n0,度(节点拥有子树的个数)为2的子节点数量为n2

      4、具有n个节点的完全二叉树的深度为deep=log2 n +1;

      

    六、二叉树-顺序存储

      顺序存储指的是充分利用满二叉树的特性,每层的节点数分别是1、2、4、8.......2的i-1次方

       缺陷:如果右节点过多时会产生空间浪费,数组中会产生好多空余数组元素。

    package com.zxc.TreeLearning.BinaryTreeLearning;
    
    import org.junit.Test;
    
    /**
     * Created by Administrator on 2018/2/19 0019.
     * 二叉树顺序存储
     */
    public class BinaryTreeA {
        private Object[] datas;//使用数组来记录该树的所有节点
        private int DEFAULT_DEEP=8;//保存该树的深度
        private int arraySize;//二叉树中总节点的个数
        private int deep;
    
        public void init(String data){
            this.deep=DEFAULT_DEEP;
            this.arraySize=(int)Math.pow(2,deep)-1;//按照满二叉树开的节点个数
            datas=new Object[arraySize];
            datas[0]=data;
        }
    
        public void add(int index,String data,boolean left){
            if(datas[index]==null){
                throw new RuntimeException(index+"处节点为空,无法添加子节点");
            }
            if(2*index+1>=arraySize){//右越界左肯定越界,所以判断左节点
                throw new RuntimeException("树底层的数组已满,树越界异常");
            }
            if(left){//左节点
                datas[2*index+1]=data;
            }else{//右节点
                datas[2*index+2]=data;
            }
        }
    
        /**
         *
         * @param index:父节点索引
         * @return 返回左子节点的数据
         */
        public String left(int index){
            return datas[2*index+1].toString();
        }
    
        /**
         *
         * @param index:父节点索引
         * @return 返回右子节点的数据
         */
        public String right(int index){
            return datas[2*index+2].toString();
        }
    
        @Test
        public void test(){
            this.init("A");
            this.add(0,"B",true);
            this.add(0,"C",false);
            System.out.println(this.left(0));
            System.out.println(this.right(0));
        }
    }

     七、二叉链式存储

    利用链表特性,每个节点都有左节点和右节点

    package com.zxc.TreeLearning.BinaryTreeLearning;
    
    import org.junit.Test;
    import sun.reflect.generics.tree.Tree;
    
    /**
     * Created by Administrator on 2018/2/20 0020.
     * 二叉链表存储
     */
    public class BinaryTreeB {
        public static class TreeNode{
            String data;
            TreeNode left;
            TreeNode right;
    
            public TreeNode() {
            }
    
            public TreeNode(String data) {
                this.data = data;
            }
    
            public TreeNode(String data, TreeNode left, TreeNode right) {
                this.data = data;
                this.left = left;
                this.right = right;
            }
        }
        //根节点
        private TreeNode root;
    
    
    
        /**
         *
         * @param parent 父节点对象
         * @param data  新增节点数据
         * @param isLeft  是否为新增左子节点
         * @return 返回新增的节点
         */
        public TreeNode addNode(TreeNode parent,String data,boolean isLeft){
            if(parent==null){
                System.out.println("不能增加子节点,父节点为空");
                return null;
            }
            if(isLeft&&parent.left!=null){
                System.out.println("左子节点已经存在,不能增加子节点");
                return null;
            }
            if(!isLeft&&parent.right!=null){
                System.out.println("右子节点已经存在,不能添加");
                return null;
            }
    
            TreeNode node=new TreeNode(data);
            if(isLeft){
                parent.left=node;
            }else{
                parent.right=node;
            }
            return node;
        }
    
        /**
         *
         * @param parent 父节点对象
         * @return 返回左子节点数据
         */
        public String leftChild(TreeNode parent){
            if(parent==null){
                throw new RuntimeException(parent+"节点为null,无法添加子节点");
            }
            return parent.left==null?null:(String)parent.left.data;
        }
    
        /**
         *
         * @param parent 需要查询的父节点对象
         * @return 返回右子节点数据
         */
        public String rightChild(TreeNode parent){
            if(parent==null){
                throw new RuntimeException(parent+"节点为null,无法添加子节点");
            }
            return parent.left==null?null:(String)parent.right.data;
        }
    
        /**
         *
         * @param node:判断的当前节点
         * @return :当前节点的深度
         */
        public int deep(TreeNode node){
            if(node==null){
                return 0;
            }
            if(node.left==null&&node.right==null){
                return 1;
            }
    
            int leftdeep=deep(node.left);
            int rightdeep=deep(node.right);
            int max=0;
            max=leftdeep>rightdeep?leftdeep:rightdeep;
            return ++max;
        }
    
        public void init(String data){
            this.root=new TreeNode(data);
            TreeNode a=this.addNode(this.root,"A",true);
            TreeNode b=this.addNode(this.root,"B",false);
            TreeNode c=this.addNode(a,"C",true);
            TreeNode d=this.addNode(a,"D",false);
            System.out.println(this.leftChild(a));
            System.out.println(this.rightChild(a));
            System.out.println(this.deep(a));
        }
    
        @Test
        public void test(){
            init("Root");
        }
    }

    缺陷:遍历树的时候效率不高,指定节点访问其父节点时也比较困难。

    八、二叉树遍历  

      1、二叉树的先序遍历(DLR)

        若二叉树为空,则不进行任何操作,否则

          1、访问根节点

          2、先序方式遍历左子树

          3、先序遍历右子树

      ABDECF

      2、二叉树的中序遍历(LDR)  投影法遍历

        若二叉树为空,则不进行任何操作,否则

          1、中序遍历左子树

          2、访问根节点

          3、中序遍历右子树

      3、二叉树的后序遍历(LRD)

        若二叉树为空,则不进行任何操作,否则

          1、后序遍历左子树

          2、后序遍历右子树

          3、访问根节点

    结果为 DEBFCA

    package com.zxc.TreeLearning.BinaryTreeLearning;
    
    import org.junit.Test;
    
    /**
     * Created by Administrator on 2018/2/20 0020.
     * 遍历二叉树,先序(DLR),中序(LDR),后序(LRD)
     */
    public class BinaryTreeSearch {
        class TreeNode{
            private String data;
            private TreeNode leftNode;
            private TreeNode rightNode;
            public TreeNode(String data,TreeNode leftNode,TreeNode rightNode){
                this.data=data;
                this.leftNode=leftNode;
                this.rightNode=rightNode;
            }
            public String getData(){
                return data;
            }
            public TreeNode getLeftNode(){
                return leftNode;
            }
            public TreeNode getRightNode(){
                return rightNode;
            }
        }
    
        public void printNode(TreeNode node){
            System.out.println(node.getData());
        }
    
        //初始化二叉树
        /*
         *                     A
         *                 /        
         *              B             C
         *             /           /   
         *           D    E       F       G
         *            /             /
         *              H   I       J   P
         *
         */
    
        @Test
        public void init(){
            TreeNode D=new TreeNode("D",null,null);
            TreeNode H=new TreeNode("H",null,null);
            TreeNode I=new TreeNode("I",null,null);
            TreeNode E=new TreeNode("E",H,I);
            TreeNode B=new TreeNode("B",D,E);
            TreeNode J=new TreeNode("J",null,null);
            TreeNode P=new TreeNode("P",null,null);
            TreeNode F=new TreeNode("F",null,J);
            TreeNode G=new TreeNode("G",P,null);
            TreeNode C=new TreeNode("C",F,G);
            TreeNode A=new TreeNode("A",B,C);
            pre(A);
            System.out.println();
            middle(A);
            System.out.println();
            last(A);
            System.out.println();
        }
    
        /**
         * 先序遍历
         * @param node 从node处先序遍历
         */
        public void pre(TreeNode node){
            System.out.print(node.data);
            if(node.leftNode!=null){
                this.pre(node.leftNode);
            }
            if(node.rightNode!=null){
                this.pre(node.rightNode);
            }
        }
    
        /**
         * 中序排序
         * @param node 从node处开始中序遍历
         */
        public void middle(TreeNode node){
            if(node.leftNode!=null){
                this.middle(node.leftNode);
            }
            System.out.print(node.data);
            if(node.rightNode!=null){
                this.middle(node.rightNode);
            }
    
        }
    
        /**
         * 后序排序
         * @param node 从node处开始后序遍历
         */
        public void last(TreeNode node){
            if(node.leftNode!=null){
                this.last(node.leftNode);
            }
            if(node.rightNode!=null){
                this.last(node.rightNode);
            }
            System.out.print(node.data);
    
        }
    }

    九、二叉树的深度、广度优先搜索

      深度优先搜索就是先序遍历

      广度优先搜索就是按照层,从根开始依次从左向右,从上到下进行遍历输出。

    package com.zxc.TreeLearning.BinaryTreeLearning;
    
    import org.junit.Test;
    import sun.reflect.generics.tree.Tree;
    
    import java.util.ArrayDeque;
    import java.util.Stack;
    
    /**
     * Created by Administrator on 2018/2/20 0020.
     * 遍历二叉树,先序(DLR),中序(LDR),后序(LRD)
     */
    public class BinaryTreeDW {
        class TreeNode{
            private String data;
            private TreeNode leftNode;
            private TreeNode rightNode;
            public TreeNode(String data,TreeNode leftNode,TreeNode rightNode){
                this.data=data;
                this.leftNode=leftNode;
                this.rightNode=rightNode;
            }
            public String getData(){
                return data;
            }
            public TreeNode getLeftNode(){
                return leftNode;
            }
            public TreeNode getRightNode(){
                return rightNode;
            }
        }
    
        public void printNode(TreeNode node){
            System.out.println(node.getData());
        }
    
        //初始化二叉树
        /*
         *                     A
         *                 /        
         *              B             C
         *             /           /   
         *           D    E       F       G
         *            /             /
         *              H   I       J   P
         *
         */
    
        /**
         * 深度优先搜索,实际上就是一个DLR,即先序遍历
         */
        public void depthOrderTraversal(){
            if(this.root==null){
                System.out.println("不能深搜,因为没有根节点");
                return ;
            }
            Stack<TreeNode> stack=new Stack<>();
            stack.push(this.root);
            while(stack.isEmpty()!=true){
                TreeNode node= stack.pop();
                System.out.print(node.data);
                if(node.getRightNode()!=null){
                    stack.push(node.rightNode);
                }
                if(node.getLeftNode()!=null){
                    stack.push(node.leftNode);
                }
            }
        }
    
        /**
         * 广度优先搜索
         */
        public void levelOrderTraversal(){
            if(this.root==null){
                System.out.println("不能深度,因为没有根节点");
            }//使用队列功能,先进先出
            ArrayDeque<TreeNode> ad=new ArrayDeque();
            ad.add(this.root);
            while(!ad.isEmpty()){
                TreeNode node=ad.remove();
                System.out.println(node.data);
                if(node.leftNode!=null){
                    ad.add(node.leftNode);
                }
                if(node.rightNode!=null){
                    ad.add(node.rightNode);
                }
            }
        }
    
        private TreeNode root;
        @Test
        public void init(){
            TreeNode D=new TreeNode("D",null,null);
            TreeNode H=new TreeNode("H",null,null);
            TreeNode I=new TreeNode("I",null,null);
            TreeNode E=new TreeNode("E",H,I);
            TreeNode B=new TreeNode("B",D,E);
            TreeNode J=new TreeNode("J",null,null);
            TreeNode P=new TreeNode("P",null,null);
            TreeNode F=new TreeNode("F",null,J);
            TreeNode G=new TreeNode("G",P,null);
            TreeNode C=new TreeNode("C",F,G);
            TreeNode A=new TreeNode("A",B,C);
            root=A;
            depthOrderTraversal();
        }
    
    }

       

  • 相关阅读:
    2021年中国DevOps现状调查报告发布!
    带你看清梦饷集团如何成为上海在线新经济四小龙
    AI论文解读丨融合视觉、语义、关系多模态信息的文档版面分析架构VSR
    云图说 | 华为云医疗智能体,智联大健康,AI药物研发
    带你走进“华为链”
    初学者入门知识图谱必看的能力:推理
    带你探索CPU调度的奥秘
    鸿蒙轻内核定时器Swtmr:不受硬件和数量限制,满足用户需求
    FLINK基础(137):DS流与表转换(3) Handling of (Insert-Only) Streams(2)fromDataStream(FLINK1.13以上)
    FLINK基础(136):DS流与表转换(2) Handling of (Insert-Only) Streams(1)简介(FLINK1.13以上)
  • 原文地址:https://www.cnblogs.com/television/p/8454503.html
Copyright © 2011-2022 走看看