树-二叉树存储及遍历

一、二叉树的概述

 

二、树和二叉树的区别

  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();
    }

}

 

   

posted @ 2018-02-19 21:44  彩电  阅读(570)  评论(0编辑  收藏  举报