因为二叉树不属于线性结构,所以当使用二叉链表来存储二叉树的时候与之前的其他线性结构(栈、单链表、双链表等)有明显的不同。
注意的地方:
1.提供的内部类定义成静态的、公共的,之前在使用链表实现其他线性结构的数据结构时,基本上使用的都是私有的非静态的内部类。内部类中设有指向左孩子和右孩子的节点以及存放数据的变量。
2.使用二叉链表存储二叉树后,对二叉树的操作与使用数组存储二叉树有明显的不同。
3.在获取二叉树的深度的时候使用了递归调用
二叉树二叉链表存储的java实现
java的实现代码如下:
public class TwoLinkBinTree<T> {
/*
* 使用java实现二叉树的二叉链表存储
* 注意:因为二叉树不是线性结构,当使用顺序存储(数组)时和其他线性结构的操作差别不是很大,
* 但是如果使用二叉链表来存储时,则差别很大!具体的差别见如下代码实现。
* 要求:
* 1.定义一个私有的内部类,用来存储节点信息
* 2.定义一个私有的节点变量,用来指向根节点
* 3.提供诺干方法用来操作二叉树
* */
public static class Node{
Object data;
Node left;
Node right;
public Node(){
}
public Node(Object data){
this.data=data;
this.left=null;
this.right=null;
}
public Node(Object data,Node left,Node right){
this.data=data;
this.left=left;
this.right=right;
}
}
private Node root;
//默认的无参构造函数
public TwoLinkBinTree(){
root = new Node();
}
//根据提供的元素构造二叉树
public TwoLinkBinTree(T data){
root = new Node(data);
}
//为指定节点添加子节点
public Node add(Node parent,T data,boolean isLeft){
//如果提供的节点为空,则不能添加子节点
if(parent==null||parent.data==null){
throw new RuntimeException("节点为空的不能添加子节点");
}
Node node=null;
if(isLeft){//如果要添加的是左子节点
if(parent.left!=null){
throw new RuntimeException("该节点的左子节点已经存在");
}else{
node=new Node(data);
parent.left=node;
}
}else{//否则添加的是右子节点
if(parent.right!=null){
throw new RuntimeException("该节点的右子节点已经存在");
}else{
node=new Node(data);
parent.right=node;
}
}
return node;
}
//判断二叉树是否为空
public boolean isEmpty(){
//这里之所以是对data进行判断是因为提供的构造函数都能够保证root不为空,但是data有可能为空
return root.data==null;
}
//获取根节点
public Node getRoot(){
if(isEmpty()){
throw new RuntimeException("树为空,不能获取根节点");
}
return root;
}
//如果使用的是无参的二叉树构造函数,则可以调用这个方法为root的data设置值
public void setRootData(T data){
if(root!=null&&root.data==null){
root.data=data;
}else{
throw new RuntimeException("该根节点已经有数据,不能重新设置");
}
}
//获取指定节点的左子节点
public Node getLeft(Node parent){
if(parent==null){
throw new RuntimeException("该根节点为空没有左子节点");
}else{
return parent.left;
}
}
//获取指定节点的右子节点
public Node getRight(Node parent){
if(parent==null){
throw new RuntimeException("该根节点为空没有右子节点");
}else{
return parent.right;
}
}
//获取二叉树的深度
public int getDeep(){
return deep(root);
}
//获取指定节点之下的深度
private int deep(Node node){
if(node==null){
return 0;
}
if(node.left==null&&node.right==null){
return 1;
}else{//采用递归的算法,遍历整个二叉树,每次将节点的最大深度(左子树、右子树深度不一致)传递给父节点
int leftDeep=deep(node.left);
int rightDeep=deep(node.right);
//去深度最大值
int max=leftDeep>rightDeep?leftDeep:rightDeep;
return max+1;
}
}
}
对于这种二叉链表的二叉树,因为采用链表来记录树中所有节点,所以添加节点没有限制,而且不会希像顺序存储那样产生大量的空间浪费。当然,这种二叉链表的存储方式在遍历树节点时效率不高,指定节点访问其父节点时也是如此,程序必须采用遍历二叉树的方式来搜寻其父节点。至于二叉树的遍历方式我会在接下来的另外一篇博客做详细的介绍。
接下来是二叉树的三叉链表实现,加油!