二叉树设计(一)

二叉树链式存储结构下,有两种基本的实现方法:(1)首先设计二叉树结点类,然后在二叉树结点类的基础上,用static成员函数实现对二叉树的操作,把这些函数封装在一个类中。(2)也是在二叉树结点类的基础上,再设计一个二叉树类来实现。

大白话翻译:其实第一种方法就是给一个结点的散点类,给一个对二叉树操作(如遍历)的类,然后你要在主函数中通过结点类把一堆散点拼接成树,再用操作类里的函数对树操作。第二种方法嘞~就是给你一个结点的散点类,给一个二叉树类,在二叉树类里完成了把散点拼接成树的具体步骤功能,并封装了操作(如遍历),然后你在主函数里只用通过二叉树类构造函数来造树就行,然后再用类里的方法操作树。(纯属个人闲扯)

二叉树是一种非线性结构,不能用简单循环遍历,所以采用递归实现,遍历操作是其他许多操作的基础,所以我们只讨论遍历。

注:遍历后的序列一定是线性且唯一的。

首先,设计二叉树结点类:

package Tree;
/**
* @author sun
* 创建时间:2017年4月22日下午4:02:5
*/
//链式存储:设计二叉树结点类,然后再该类基础上,用static成员函数实现而产生的操作
public class BiTreeNode {
	private BiTreeNode leftChild;//左孩子结点对象引用
	private BiTreeNode rightChild;//右孩子结点对象引用
	public Object data;//数据元素
	
	BiTreeNode(){//可用于带头结点结构中头结点创建。
		leftChild = null;
		rightChild = null;
	}
	
	BiTreeNode(Object item,BiTreeNode left,BiTreeNode right){
		data = item;
		leftChild = left;
		rightChild = right;
	}
	
	public BiTreeNode getLeft(){
		return leftChild;
	}
	
	public BiTreeNode getRight(){
		return rightChild;
	}
	
	public Object getData(){
		return data;
	}
}

遍历:根据访问根结点的次序分为前序遍历(DLR)、中序遍历(LDR)、后序遍历(LRD)这三个不再赘述。

还有一个是层序遍历:按二叉树的层序次序,同一层中按先左子树再右子树的次序遍历二叉树。遍历特点:在所有未被访问结点的集合中,排列在已访问结点集合中最前面(先被访问的)结点的左子树的根结点将最先被访问,然后是右子树根结点。

故根据特点采用队列实现:(1)初始化队列;(2)根结点指针如队列;(3)当队列非空执行:a、出队列访问(输出)队头结点,b、若其左孩子非空,入队列,c、若其右孩子非空,入队列;(4)结束。

注:给定一棵二叉树的前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树的结构。

“访问该结点”就是拿一个结点对其进行需要的操作,所以我们可以把对一个结点的操作也封装起来,这里只输出:

package Tree;
/**
* @author sun
* 创建时间:2017年4月22日下午5:25:22
*/
//设计一个访问类,表示访问该结点并进行操作,这里操作只输出
public class Visit {
	public void print(Object item){
		System.out.print(item+" ");
	}
}

接下来,我们先看二叉树实现的第一种方法,设计对二叉树的操作类:

package Tree;

import StackAndQueue.LinQueue;//因为层序遍历用到队列

/**
* @author sun
* 创建时间:2017年4月22日下午5:27:31
*/
//二叉树遍历类
public class Traverse {
	public static void preOrder(BiTreeNode t,Visit vs){
	//前序遍历二叉树t,访问结点操作为vs.print(t.data)
		if(t!=null){
			vs.print(t.data);
			preOrder(t.getLeft(),vs);
			preOrder(t.getRight(),vs);
		}
	}
	
	public static void inOrder(BiTreeNode t,Visit vs){
	//中序遍历二叉树t
		if(t!=null){
			inOrder(t.getLeft(),vs);
			vs.print(t.data);
			inOrder(t.getRight(),vs);
		}
	}
	
	public static void postOrder(BiTreeNode t,Visit vs){
	//后序遍历二叉树t
		if(t!=null){
			postOrder(t.getLeft(),vs);
			postOrder(t.getRight(),vs);
			vs.print(t.data);
		}
	}
	
	public static void levelOrder(BiTreeNode t,Visit vs)throws Exception{
	//层序遍历二叉树t
		LinQueue q = new LinQueue();//创建链式队列类对象
		if(t==null) return;
		BiTreeNode curr;
		q.append(t);//根结点入队列
		while(q.notEmpty()){//当队列非空时循环
			curr = (BiTreeNode)q.delete();//出队列
			vs.print(curr.data);//访问该结点
			if(curr.getLeft()!=null)
				q.append(curr.getLeft());//左孩子结点入队列
			if(curr.getRight()!=null)
				q.append(curr.getRight());//右孩子结点入队列
		}
	}
}

接下来用主函数测试遍历,并添加两个功能(1)打印二叉树(2)回溯查找数据元素

package Tree;
/**
* @author sun
* 创建时间:2017年4月23日下午2:24:59
*/
//实现二叉树遍历,打印和查找等操作
public class TestMyTree {
	//打印是把二叉树逆时针旋转90°,按照凹入表示法打印,从上往下就是右树、根、左树(中序)
	public static void printBiTree(BiTreeNode root,int level){
	//二叉树root各层结点数据元素值的横向输出,level为root结点所在整个树的层次
		if(root!=null){
		//子二叉树root.getRight()第level+1层结点数据元素值的横向输出
			printBiTree(root.getRight(),level+1);
			if(level!=0){
				//打出空格更有层次感,设定6*(level-1)个空格
				for(int i=0;i<6*(level-1);i++){
					System.out.print(" ");
				}
				System.out.print("---");//输出横线也是为了好看
			}
			System.out.println(root.data);//输出结点的数据元素值
		//子二叉树root.getLeft()第level+1层结点数据元素值的横向输出
			printBiTree(root.getLeft(),level+1);
		}
	}
	
	public static BiTreeNode search(BiTreeNode t,Object x){
	//在二叉树t中查找数据元素x,回溯法应用,采用前序遍历
		BiTreeNode temp;
		if(t==null) return null;
		if(t.data.equals(x)) return t;//当前结点(根结点)值等x则查找成功输出
		if(t.getLeft()!=null){
			temp = search(t.getLeft(),x);//在左子树查找
			if(temp!=null) return temp;//查找成功
		}
		if(t.getRight()!=null){
			temp = search(t.getRight(),x);//在右子树查找
			if(temp!=null) return temp;//查找成功
		}
		return null;//查找失败
	}
	
	public static BiTreeNode getTreeNode(Object item,BiTreeNode left,BiTreeNode right){
	//构造二叉树的结点
		BiTreeNode temp = new BiTreeNode(item,left,right);
		return temp;
	}
	
	public static BiTreeNode makeTree(){
	//构造一个不带头结点的二叉链存储结构的二叉树
		BiTreeNode b,c,d,e,f,g;
		g = getTreeNode(new Character('G'),null,null);
		d = getTreeNode(new Character('D'),null,g);
		b = getTreeNode(new Character('B'),d,null);
		e = getTreeNode(new Character('E'),null,null);
		f = getTreeNode(new Character('F'),null,null);
		c = getTreeNode(new Character('C'),e,f);
		return getTreeNode(new Character('A'),b,c);
	}
	
	public static void main(String[] args) {
		BiTreeNode root1;
		BiTreeNode temp;
		Visit vs = new Visit();//用于对结点操作
		
		root1 = makeTree();
		System.out.println("二叉树为:");
		printBiTree(root1,0);//横向打印
		System.out.println();
		
		System.out.print("前序遍历结点序列为:");
		Traverse.inOrder(root1, vs);
		System.out.println();
		
		System.out.print("中序遍历结点序列为:");
		Traverse.postOrder(root1, vs);
		System.out.println();
		
		System.out.print("后序遍历结点序列为:");
		Traverse.preOrder(root1, vs);
		System.out.println();
		
		System.out.print("层序遍历结点序列为:");
		try{
			Traverse.levelOrder(root1, vs);
		}
		catch(Exception e){
			e.printStackTrace();
		}
		System.out.println();
		
		temp = search(root1,new Character('C'));
		if(temp!=null)
			System.out.println("查找到的结点数据值为:"+temp.data);
		else
			System.out.println("查找失败");
	}
}
/*
 * 二叉树为:
      ---F
---C
      ---E
A
---B
            ---G
      ---D

前序遍历结点序列为:D G B A E C F 
中序遍历结点序列为:G D B E F C A 
后序遍历结点序列为:A B D G C E F 
层序遍历结点序列为:A B C D E F G 
查找到的结点数据值为:C
*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值