二叉树的链式实现


相关术语:

平衡树,非平衡树,完全数,满树。

实现策略:

1)数组实现

这个还是非常重要的,有时间写一下,先用链来写

元素n的(从0开始按层编号)左子树编号为2n+1,右子树编号为2n+2,数学证明就略了,用这个来控制下标

2)模拟链式实现

3)链式实现


树是一种非线性结构,那么跟前不一样,必须根据你的需求来构造新的节点才能满足树中的节点特征

 
  
package Tree;

public class BinaryTreeNode {

protected Object element;
protected BinaryTreeNode left,right;


public BinaryTreeNode(Object element) // 用元素来构造一个结点
{
this .element = element;
left
= null ;
right
= null ;
}

public int numChildren(){ // 返回结点的子树上结点的个数

int count = 0 ;
if (left != null )
count
= 1 + left.numChildren();
if (right != null )
count
= count + 1 + right.numChildren();
return count;
}

}


下面是一个实现了一些基本操作的二叉树的ADT:主要是三种遍历方式

ContractedBlock.gif ExpandedBlockStart.gif BinaryTreeADT
 
   
package Tree;

import java.util.Iterator; // 引入迭代器后,对于遍历就直接将遍历的方法写在了迭代器中

public interface BinaryTreeADT {

public int size();

public boolean isEmpty();

public boolean contains(Object element);

public void removeLeftSubtree(); // 删除左子树

public void removeRightSubtree(); // 删除右子树

public Object find(Object targetelement); // 找到某个元素并返回其引用

public String toString(); // 返回树的字符串表示

public Iterator iteratorInorder(); // 返回中序遍历的迭代器

public Iterator PreInorder(); // 返回前序遍历的迭代器

public Iterator PostInorder(); // 返回后序遍历的迭代器

// public Iterator LevelInorder(); // 返回层次遍历的迭代器

}



下面来实现:

维护一个根节点和count变量来记录总共的节点数,以及下面的构造方法:

 
  
private int count;
protected BinaryTreeNode root;

// 3个构造方法

public BinaryTree()
{
root
= null ;
count
= 0 ;
}

public BinaryTree(Object element)
{
root
= new BinaryTreeNode(element);
count
= 1 ;
}

public BinaryTree(Object element,BinaryTree leftSubtree,BinaryTree rightSubtree)
{
root
= new BinaryTreeNode(element);
count
= 1 ;
if (leftSubtree != null )
{
count
= count + leftSubtree.size();
root.left
= leftSubtree.root;
}
else root.left = null ;

if (rightSubtree != null )
{
count
= count + rightSubtree.size();
root.right
= rightSubtree.root;
}
else root.right = null ;
}



主要来看一下遍历的实现,把遍历写成一个迭代器(在链表里写了很多代码,感觉很憋屈,很多地方都花在遍历和迭代上,就是因为没有去实现Iterator)


在遍历中,要用到队列,先来看下队列迭代器是怎么实现的:

在前面写的队列LinkedQueue中,添加一个返回值为Iterator的方法:

 
  
public Iterator iterator(){
return new LinkedQueueIterator(front,rear,count);
}


它实际上是返回 另一个继承了Iterator类的类的对象,这个对象的构造函数一般来说是由LinkedQueue里的成员变量组成的(因为要实现Iterator里面的方法):

 
  
package Queue;

import java.util.Iterator;

import Bag.LinearNode;

public class LinkedQueueIterator implements Iterator {

private LinearNode front,rear,current;
private int count;

// 迭代器类的构造器
public LinkedQueueIterator(LinearNode front,LinearNode rear, int count)
{
this .front = front;
this .rear = rear;
this .count = count;
this .current = front;
}


public boolean hasNext() {

return (current != null );
}

public Object next() {
Object result
= current.getElement();
current
= current.getNext();
return result;
}

public void remove() {

}

}


上面说明了怎么去实现一个数据结构的迭代器,关键在于 去实现特定于自身数据结构的Iterator方法(hasNext,next,remove)

在树的遍历中,需要借助于队列的迭代器,来返回一个树的迭代器,将树中元素按照遍历规则入队,最后返回队列的迭代器,这个迭代器就是树的迭代器。


中序遍历迭代器的实现(前序后序类似):借助于一个private的支持方法来将树中元素按序进队:

 
  
public Iterator iteratorInorder() {

LinkedQueue queue
= new LinkedQueue();
inorder(root,queue);
// 将以root为根的树按序进队
return queue.iterator(); // 返回队列的迭代器
}

private void inorder(BinaryTreeNode node,LinkedQueue queue){
if (node != null )
{
inorder(node.left,queue);
queue.enqueue(node.element);
inorder(node.right,queue);
}
}


将遍历写成迭代迭代器会有利于很多后序操作,当然,也可以直接写一个遍历输出元素:

 
  
// 直接写一个遍历的方法,不用迭代器也行
// public static void previsit(BinaryTreeNode node){
// if(node != null)
// {
// System.out.println(node.element);
// previsit(node.left);
// previsit(node.right);
// }

// }


其他操作参见注释,不再分析实现,清单代码:

ContractedBlock.gif ExpandedBlockStart.gif BinaryTree
 
   
package Tree;

import java.util.Iterator;

import Queue.LinkedQueue;

public class BinaryTree implements BinaryTreeADT {

private int count;
protected BinaryTreeNode root;

// 3个构造方法

public BinaryTree()
{
root
= null ;
count
= 0 ;
}

public BinaryTree(Object element)
{
root
= new BinaryTreeNode(element);
count
= 1 ;
}

public BinaryTree(Object element,BinaryTree leftSubtree,BinaryTree rightSubtree)
{
root
= new BinaryTreeNode(element);
count
= 1 ;
if (leftSubtree != null )
{
count
= count + leftSubtree.size();
root.left
= leftSubtree.root;
}
else root.left = null ;

if (rightSubtree != null )
{
count
= count + rightSubtree.size();
root.right
= rightSubtree.root;
}
else root.right = null ;
}



// 接口定义的操作

public int size() {
return count;
}

public boolean isEmpty() {
return (count == 0 );
}

public void removeLeftSubtree() {
if (root.left != null )
count
= count - 1 - root.left.numChildren();
root.left
= null ;
}

public void removeRightSubtree() {
if (root.right != null )
count
= count - 1 - root.right.numChildren();
root.right
= null ;
}

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) {
if (find(element) != null )
return true ;
return false ;
}


public Iterator iteratorInorder() {

LinkedQueue queue
= new LinkedQueue();
inorder(root,queue);
// 将以root为根的树按序进队
return queue.iterator(); // 返回队列的迭代器
}

private void inorder(BinaryTreeNode node,LinkedQueue queue){
if (node != null )
{
inorder(node.left,queue);
queue.enqueue(node.element);
inorder(node.right,queue);
}
}


public Iterator PreInorder() {
LinkedQueue queue
= new LinkedQueue();
preorder(root,queue);
return queue.iterator();
}

private void preorder(BinaryTreeNode node,LinkedQueue queue){
if (node != null )
{
queue.enqueue(node.element);
preorder(node.left,queue);
preorder(node.right,queue);
}
}

public Iterator PostInorder() {
LinkedQueue queue
= new LinkedQueue();
postorder(root,queue);
return queue.iterator();
}

private void postorder(BinaryTreeNode node,LinkedQueue queue){
if (node != null )
{
postorder(node.left,queue);
postorder(node.right,queue);
queue.enqueue(node.element);
}
}

// 直接写一个遍历的方法,不用迭代器也行
// public static void previsit(BinaryTreeNode node){
// if(node != null)
// {
// System.out.println(node.element);
// previsit(node.left);
// previsit(node.right);
// }

// }

public static void main(String[] args) {

BinaryTree tree3
= new BinaryTree ( 3 );
BinaryTree tree4
= new BinaryTree ( 4 );
BinaryTree tree2
= new BinaryTree( 2 ,tree3,tree4);

BinaryTree tree7
= new BinaryTree ( 7 );
BinaryTree tree6
= new BinaryTree ( 6 ,tree7, null );

BinaryTree tree5
= new BinaryTree ( 5 , null ,tree6);

BinaryTree tree1
= new BinaryTree ( 1 ,tree2,tree5);

System.out.println(
" 树的大小是: " + tree1.size());
System.out.println(
" 树为空吗?: " + tree1.isEmpty());


// previsit(tree1.root);

System.out.println(
" \n中序遍历结果为: " );
Iterator it
= tree1.iteratorInorder();
while (it.hasNext())
System.out.print(it.next()
+ " " );

System.out.println(
" \n前序遍历结果为: " );
it
= tree1.PreInorder();
while (it.hasNext())
System.out.print(it.next()
+ " " );

System.out.println(
" \n后序遍历结果为: " );
it
= tree1.PostInorder();
while (it.hasNext())
System.out.print(it.next()
+ " " );

System.out.println(
" \n\n " + tree1.find( 0 ));
System.out.println(
" 包含元素6吗?: " + tree1.contains( 6 ));
System.out.println(
" 包含元素8吗?: " + tree1.contains( 8 ));



tree1.removeLeftSubtree();
System.out.println(
" \n删除左子树后中序遍历结果为: " );
it
= tree1.iteratorInorder();
while (it.hasNext())
System.out.print(it.next()
+ " " );

}

}



你会发现,并没有去实现add和delete操作,因为在具体的应用需求之前,并不知道该怎么去添加和删除,它不像线性结构,添加和删除后是要调整树的形状的。

由于没有写一个addleft,addright方法,构造一个树来测试显得很冗长,在main方法前面好多行,构造了下面的二叉树:

2011050822503822.jpg


结果如下:


树的大小是: 7
树为空吗?: false

中序遍历结果为:
3 2 4 1 5 7 6
前序遍历结果为:
1 2 3 4 5 6 7
后序遍历结果为:
3 4 2 7 6 5 1

null
包含元素6吗?: true
包含元素8吗?: false

删除左子树后中序遍历结果为:
1 5 7 6



转载于:https://www.cnblogs.com/jmzz/archive/2011/05/08/2040664.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值