二叉树的数组实现
存储方案:
用数组来实现二叉树,树上的元素存放位置在数组中是固定的---如果树的i位置(从0开始按层编号)有元素,就放在数组的i号位置,没有元素,数组对应的位置就空着。i的左右子树的编号为2i+1和2i+2。
1,实例变量,容量动态扩展,以及构造方法:
protected Object[] contents;
protected int count;//count表示树中节点数,不是数组当前最后一个可用的下标
//一些构造函数和必备的支持方法
public ArrayBinaryTree(Object root)
{
//Object[] contents = new Object[10]; 悲剧啊!!!!局部变量覆盖了类成员变量
contents = new Object[10];
contents[0] = root;
count = 1;
}
public void expand()
{
//Object[] larger = new Object[size()*3];
Object[] larger = new Object[contents.length*3];
for(int i = 0;i < contents.length;i++)
larger[i] = contents[i];
contents = larger;
}
注意几点:
1)count并不是数组的大小,上面说过,数组中会有很多空置的下标。
2)如上注释处的错误:
在构造函数中Object[] contents = new Object[10];
这是重新 声明 + 初始化了一个局部变量,这个contents将覆盖实例变量contents,很隐蔽的错误,调试了半天才发现
2,为了方便建树测试,跟链式实现不一样,我重新定义了2个方法addLeft,addRight,见代码清单
3,遍历,思路同链式实现,仍是借助于队列,将元素按规定的遍历方式进队,返回队列的迭代器。
不一样的就是数组是用下标来控制的,随时要注意扩展数组容量和防止下标越界:
中序遍历迭代器:
public Iterator iteratorInorder() {
LinkedQueue queue = new LinkedQueue();
inorder(0,queue);
return queue.iterator();
}
private void inorder(int index,LinkedQueue queue){
if(index < contents.length && contents[index] != null)
{
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(lindex < contents.length && contents[lindex] != null)
inorder(lindex,queue);//左子树递归
queue.enqueue(contents[index]);//根节点进队
if(rindex < contents.length && contents[rindex] != null)
inorder(rindex,queue);//右子树递归
}
}
4,删除子树,在链式实现里非常简单,直接将子节点置null即可,用数组比较麻烦,这里我定义一个递归的方法,借助它可以删除指定下标index的子树(将index左右子树上的结点全部置为null)
private void removeSubtree(int index){//删除contents[index]的左右子树(递归)
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(lindex < contents.length && contents[lindex] != null)
{
contents[lindex] = null;
count--;
removeSubtree(lindex);
}
//if(contents[rindex] != null) 可能数组越界
if(rindex < contents.length && contents[rindex] != null)
{
contents[rindex] = null;
count--;
removeSubtree(rindex);
}
}
5,完整清单及测试结果
ArrayBinaryTree
package Tree;
import java.util.Iterator;
import Queue.LinkedQueue;
//用数组来实现二叉查找树,树上的元素存放位置在数组中是固定的---如果树的i位置(从0开始按层编号)有元素
//,就放在数组的i号位置,没有元素,数组对应的位置就空着。i的左右子树的编号为2i+1和2i+2
public class ArrayBinaryTree implements BinaryTreeADT {
protected Object[] contents;
protected int count;//count表示树中节点数,不是数组当前最后一个可用的下标
//一些构造函数和必备的支持方法
public ArrayBinaryTree(Object root)
{
//Object[] contents = new Object[10]; 悲剧啊!!!!局部变量覆盖了类成员变量
contents = new Object[10];
contents[0] = root;
count = 1;
}
public void expand()
{
//Object[] larger = new Object[size()*3];
Object[] larger = new Object[contents.length*3];
for(int i = 0;i < contents.length;i++)
larger[i] = contents[i];
contents = larger;
}
public void addLeft(Object current,Object left)//为当前结点添加左子结点
{
for(int index = 0;index < contents.length;index++)
if(contents[index].equals(current))//找到当前节点的下标index
{
int lindex = index * 2 + 1;
if(lindex >= contents.length)
expand();
contents[lindex] = left;
count++;
return;
}
}
public void addRight(Object current,Object right)//为当前节点添加右子节点
{
for(int index = 0;index < contents.length;index++)
if(contents[index].equals(current))
{
int rindex = index * 2 + 2;
if(rindex >= contents.length)
expand();
contents[rindex] = right;
count++;
return;
}
}
//接口方法
public int size() {
return count;
}
public boolean isEmpty() {
return (size()==0);
}
public Iterator iteratorInorder() {
LinkedQueue queue = new LinkedQueue();
inorder(0,queue);
return queue.iterator();
}
private void inorder(int index,LinkedQueue queue){
if(index < contents.length && contents[index] != null)
{
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(lindex < contents.length && contents[lindex] != null)
inorder(lindex,queue);
queue.enqueue(contents[index]);
if(rindex < contents.length && contents[rindex] != null)
inorder(rindex,queue);
}
}
public Iterator PreInorder() {
LinkedQueue queue = new LinkedQueue();
preorder(0,queue);
return queue.iterator();
}
private void preorder(int index,LinkedQueue queue){
if(index < contents.length && contents[index] != null)
{
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
queue.enqueue(contents[index]);
if(lindex < contents.length && contents[lindex] != null)
preorder(lindex,queue);
if(rindex < contents.length && contents[rindex] != null)
preorder(rindex,queue);
}
}
public Iterator PostInorder() {
LinkedQueue queue = new LinkedQueue();
postorder(0,queue);
return queue.iterator();
}
private void postorder(int index,LinkedQueue queue){
if(index < contents.length && contents[index] != null)
{
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(lindex < contents.length && contents[lindex] != null)
postorder(lindex,queue);
if(rindex < contents.length && contents[rindex] != null)
postorder(rindex,queue);
queue.enqueue(contents[index]);
}
}
public Object find(Object target){
Iterator it = this.iteratorInorder();
Object result = null;
while(it.hasNext())
{
result = it.next();
if(result.equals(target))
break;
else result = null;
}
return result;
}
public boolean contains(Object element) {
return (find(element) != null);
}
public void removeLeftSubtree() {
if(contents[1] == null)
{
System.out.println("没有左子树");
return;
}
else
{
contents[1] = null;
count--;
removeSubtree(1);
}
}
public void removeRightSubtree() {
if(contents[2] == null)
{
System.out.println("没有右子树");
return;
}
else
{
contents[2] = null;
count--;
removeSubtree(2);
}
}
private void removeSubtree(int index){//删除contents[index]的左右子树(递归)
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(lindex < contents.length && contents[lindex] != null)
{
contents[lindex] = null;
count--;
removeSubtree(lindex);
}
//if(contents[rindex] != null) 可能数组越界
if(rindex < contents.length && contents[rindex] != null)
{
contents[rindex] = null;
count--;
removeSubtree(rindex);
}
}
public static void main(String[] args) {
ArrayBinaryTree tree = new ArrayBinaryTree(15);
tree.addLeft(15, 12);
tree.addRight(15, 10);
tree.addLeft(12, 13);
tree.addRight(12, 9);
tree.addLeft(10, 6);
tree.addRight(10, 11);
tree.addRight(13, 1);
tree.addLeft(9, 8);
tree.addRight(9, 5);
tree.addLeft(6, 2);
tree.addLeft(11, 7);
tree.addRight(11, 4);
System.out.println("树的大小是: " + tree.size());
System.out.println("树为空吗?: " + tree.isEmpty());
System.out.println("\n中序遍历结果为: ");
Iterator it = tree.iteratorInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
System.out.println("\n前序遍历结果为: ");
it = tree.PreInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
System.out.println("\n后序遍历结果为: ");
it = tree.PostInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
tree.removeRightSubtree();
System.out.println("\n\n删除右子树,后序遍历结果为: ");
it = tree.PostInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
System.out.println("\n\n查找元素12: " + tree.find(12));
System.out.println("查找元素11: " + tree.find(11));
System.out.println("存在元素9吗?: " + tree.contains(9));
System.out.println("存在元素7吗?: " + tree.contains(7));
}
}
在main函数里用addLeft,addRight构造了下列形状的二叉树:
结果:
树的大小是: 13
树为空吗?: false
中序遍历结果为:
13 1 12 8 9 5 15 2 6 10 7 11 4
前序遍历结果为:
15 12 13 1 9 8 5 10 6 2 11 7 4
后序遍历结果为:
1 13 8 5 9 12 2 6 7 4 11 10 15
删除右子树,后序遍历结果为:
1 13 8 5 9 12 15
查找元素12: 12
查找元素11: null
存在元素9吗?: true
存在元素7吗?: false