数组实现二叉树

来源:互联网 发布:windows运维 书籍 编辑:程序博客网 时间:2024/06/13 13:47

存储方案:

用数组来实现二叉树,树上的元素存放位置在数组中是固定的---如果树的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,完整清单及测试结果

复制代码
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
0 0