5、二叉树(上)
树中节点的度数没限制,而二叉树中树的度数最大为2,无序树的节点无左右之分,而二叉树的节点有左右之分,也即二叉树是有序树。本文主要介绍二叉树的基本性质以及二叉树的顺序存储和链式存储的实现。
两种特殊的二叉树:
- 满二叉树:指的是深度为k且含有(2^k)-1个结点的二叉树
- 完全二叉树:树中所含的 n 个结点和满二叉树中编号为 1 至 n 的结点一一对应。(编号的规则为,由上到下,从左到右)
5.1 二叉树的性质
二叉树有如下几个重要性质:
- 二叉树的第i层的节点数目最多为2^(i-1),其中i≥1
- 深度为k的二叉树最多有2^k-1个节点,深度为k的二叉树每层的节点数的最大值为等比为2的等比数列,其节点总数最多为等比数列的前k项和
- 在任何一颗二叉树中,如果叶子节点的数量为n0,度为2的节点的数量为n2,n0 = n2 + 1
- 具有n个节点的完全二叉树的深度为log2(n)+1
- 若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点:
(1) 若 i=1,则该结点是二叉树的根,无双亲,否则,编号为 i/2的结点为其双亲结点;
(2) 若 2i>n,则该结点无左孩子,否则,编号为 2i 的结点为其左孩子结点;
(3) 若 2i+1>n,则该结点无右孩子结点,否则,编号为2i+1 的结点为其右孩子结点。
5.2 二叉树的顺序存储
顺序存储指的是充分利用满二叉树的性质,满二叉树的第K层有2^(K-1)个节点,则利用一个长度为2^K-1的数组便可以保存二叉树中所有的元素。
使用数组来存储二叉树中的节点可能会产生一定的空间浪费,如果该二叉树是完全二叉树,则不会有任何浪费;如果是一颗斜二叉树,则会产生一定的空间浪费。
顺序存储的二叉树,不管是遍历树中节点还是查询树中的节点,都可以非常高效的完成,唯一的缺点是空间浪费大。
二叉树的顺序存储实现如下:
import java.util.Arrays;
/**
* 二叉树的顺序存储
* @author Administrator
*
*/
public class ArrayBinTree<T> {
//使用数组来记录所有的节点
private Object[] datas;
//定义树的默认深度
private int DEFAULT_DEEP = 8;
//保存树的深度
private int deep;
//保存数组的长度
private int arraySize;
/**
* 以默认深度创建二叉树
*/
public ArrayBinTree(){
this.deep = DEFAULT_DEEP;
arraySize = (int) (Math.pow(2,deep) - 1);
datas = new Object[arraySize];
}
/**
* 以指定深度定义二叉树
* @param deep 深度
*/
public ArrayBinTree(int deep){
this.deep = deep;
arraySize = (int) Math.pow(2, deep) - 1;
datas = new Object[arraySize];
}
/**
* 以指定深度和指定根节点创建树
* @param deep 深度
* @param data 根
*/
public ArrayBinTree(int deep,T data){
this.deep = deep;
arraySize = (int) Math.pow(2, deep) - 1;
datas = new Object[arraySize];
datas[0] = data;
}
/**
* 为指定节点添加子节点
* @param index 指定节点在数组中的索引
* @param data 要添加的数据
* @param left 添加的子节点是否为左子节点
*/
public void add(int index,T data,boolean left){
//若index处的节点为空
if(datas[index] == null){
throw new RuntimeException( index+"处的节点为空,无法添加子节点");
}
if(index * 2 +