二叉树的建立

来源:互联网 发布:ios11 蜂窝移动网络 编辑:程序博客网 时间:2024/06/07 15:52

一、二叉树简介

一般树状结构在计算机内存中以链表存储,对于n元树,每个节点的分支度不相同,因此指针域必须为孩子节点最多的个数,每个节点的数据结构如下:

这里写图片描述

假设n元树有m个节点,那么此树共享了n*m个指针域,除树根外,每个非空链接都指向一个节点,因此空链接个数为 n*m-(m-1)=m*(n-1)+1,因此n元树的链接浪费率为 m*(n-1)+1 / m*n。
当n=2时,2元树的链接浪费率为1/2
当n=3时,3元树的链接浪费率为2/3
当n=4时,4元树的链接浪费率为3/4
……
当n=2时链接浪费率最低,因此最常使用二叉树结构来取代树状结构。

二叉树定义:是一个由有限节点所组成的集合,可以为空集合,或由一个树根及左右两个子树所组成。即每个节点最多只能有两个孩子节点。

数据结构如下:
这里写图片描述

与一般树的区别:

  • 树不能为空集,但二叉树可以
  • 树的分支度为d>=0,但二叉树最多为2个
  • 树的子树间没有次序关系,二叉树必须考虑子树间的次序关系,如下图所示就是两棵不同的二叉树

这里写图片描述

二、二叉树存储方式

1、数组表示法

使用一维数组存储二叉树,将二叉树想象成一个满二叉树,数组第一个位置不用。对每层节点由从上到下、从左到右依次编号,分别将值存入数组所对应的编号的位置上。用数组来存储二叉树,越接近满二叉树越节省空间,若为歪斜树则非常浪费空间,增删数据较麻烦。

建立规则:小于父节点的值放在左子节点,大于父节点的值放在右子节点,这样可以确保左子树的值一定完全小于树根,右子树的值一定大于树根。

下来我们看一个以数组建立二叉树的实例。
例如我们用数据{6,3,5,9,7,8,4,2}按照以上规则建立的二叉树如下所示:

这里写图片描述

在内存中的情况为:

这里写图片描述

圆圈旁边的数字表示该节点在数组中的索引值,节点不存在的值为0。观察规律有,左子节点的下标是父节点下标的2倍,右子节点下标是父节点下标的2倍+1
因此对于每个值,我们从根节点开始循环,判断父节点的值是否为0,若为0则将该值放在此节点上,若不为0进入循环,判断该值与父节点的大小来决定他的下标值,依次类推,直到找到某个下标为0的空位置。

编写函数public static void buildBtree(int[] data,int[] btree),用data数组中的数据建立二叉树,存放于btree数组中。

    public static void buildBtree(int[] data,int[] btree) {        int index;                                 //索引值        for(int i=0;i<data.length;i++) {           //对原始数据的每个值进行操作            for(index=1;btree[index]!=0;) {        //父节点是否存在                if(data[i]>btree[index])           //如果数组内的值大于父节点,则往右子树比较                    index=2*index+1;                else                               //如果数组内的值小于等于父节点,则往左子树比较                    index=2*index;            }                                      //如果子树节点的值不为0,则再与数组中数据进行比较            btree[index]=data[i];                  //将值存入二叉树        }    }

编写测试代码调用上述函数:

public class Btree {    public static void main(String[] args) {        int[] data= {6,3,5,9,7,8,4,2};         //原始数据        int[] btree=new int[16];               //使用一维数组存放二叉树        System.out.println("原始数组内容:");        for(int i=0;i<8;i++)            System.out.print("["+data[i]+"] ");        System.out.println();        buildBtree(data,btree);               //调用建立二叉树的函数        System.out.println("二叉树内容为:");        for(int i=1;i<btree.length;i++)            System.out.print("["+btree[i]+"] ");        System.out.println();    }

程序运行结果如下:
这里写图片描述

2、链表表示法

定义TreeNode节点类,包含数据域、左孩子节点指针域、右孩子节点指针域。
优点:增删节点方便
缺点:很难找到父节点

//二叉树节点类声明class TreeNode{    int value;    TreeNode leftNode;                  //指向左孩子节点       TreeNode rightNode;                 //指向右孩子节点    public TreeNode(int value) {        //TreeNode类的构造函数        this.value=value;        this.leftNode=null;        this.rightNode=null;    }}

我们用data数组中的数据建立二叉树,将每个数据通过AddNodeToTree(int value)函数加入二叉树中适当的节点。首先判断根节点是否存在,若不存在则建立根节点。每次从根节点开始遍历,如果该节点小于当前节点,则判断当前节点的左孩子节点是否为空,若为空,则将该节点放在左孩子节点上,若不为空则当前节点指向原当前节点的左孩子节点继续上述比较操作。同理如果该节点大于当前节点,则判断当前节点的右孩子节点是否为空,依次循环。

建立二叉树的代码如下:

    /*建立二叉树*/    static void buildBtree(int[] data) {        for(int i=0;i<data.length;i++)             AddNodeToTree(data[i]);                                //将指定的值加入到二叉树中适当的节点    }    /*将节点加入到二叉树中*/    static void AddNodeToTree(int value) {        TreeNode currentNode=rootNode;        if(rootNode==null) {                                       //建立树根            rootNode=new TreeNode(value);            return;        }        while(true) {            if(value<currentNode.value) {                          //建立左子树                if(currentNode.leftNode==null) {                   //左孩子节点为空                    currentNode.leftNode=new TreeNode(value);      //建立左孩子节点                    return;                }                else                    currentNode=currentNode.leftNode;              //若不为空,则当前节点指向原当前节点的左孩子节点            }            else {                                                 //建立右子树                if(currentNode.rightNode==null) {                  //右孩子节点为空                    currentNode.rightNode=new TreeNode(value);     //建立右孩子节点                    return;                }                else                    currentNode=currentNode.rightNode;             //若不为空,则当前节点指向原当前节点的右孩子节点            }        }    }

编写测试代码调用上述函数:

public class Test {    static TreeNode rootNode;    public static void main(String[] args) {        int[] data= {6,3,5,9,7,8,4,2};        System.out.println("原始数组内容:");        for(int i=0;i<8;i++)            System.out.print("["+data[i]+"] ");        System.out.println();           buildBtree(data);                                          //调用buildBtree函数建立二叉树        System.out.println("以链表方式建立二叉树成功!");    }}