树之二叉树

    树形结构是一种重要的非线性结构。其中,二叉树是我们学习中的重点中的重点——因为任何一颗树通过一定的变换都能变成二叉树。每颗树都只有一个根节点。n(n>=2)棵树可以形成森林。同样,森林可以转化成普通的树,而普通的树也可以转化成森林,更可以转化成二叉树。这就对我们很有利了。因为,我们只要把大部分的时间来研究二叉树就行了。

    二叉树是每个节点至多有两颗子树的树(即二叉树不存在度大于2的节点)。而且,二叉树有严格的左右之分,不能随意互换。二叉树有很多的性质。比如说,在一颗树的第i层上至多有2^(i-1)个节点(根算作第0层)。深度为k的二叉树最多有2^k-1个节点(k>1)。对于任何一棵二叉树,如果其终端节点数为n0,度的节点数为n2,则n0 = n2 + 1。同时,具有n个节点的完全二叉树的深度为[logn/log2]+1个。

    二叉树也有很多的存储结构,比如说顺序存储结构(仅仅使用于完全二叉树)、链式存储结构(可分为两种,一种是有存储数据域、左孩子的指针域、右孩子的指针域,所得二叉树成为二叉链表,另一种除了有存储数据域、左孩子的指针域、右孩子的指针域,还有指向双亲的指针域。

    二叉树的遍历是一个重点。在Java中,我们依旧可以采用先序遍历(即先遍历根,再遍历左孩子,再右孩子)、中序遍历(即先遍历左孩子,再遍历根,最后遍历右孩子)、后序遍历(即先遍历左孩子,再遍历右孩子,最后遍历根),还有一种最容易理解的层次遍历。

    实现一个遍历,既可以用递归的方法,也可以用非递归的方法。递归容易理解,而非递归则在空间利用率上有优势。

    通过中序遍历和先序遍历或者是中序遍历和后序遍历,我们可以完全确定出一棵二叉树。

    二叉树中有最优二叉树(赫夫曼树),带权路径长度最小的二叉树便称作最优二叉树或者赫夫曼树。赫夫曼树在计算图像压缩处理、数据压缩等方面有着很大的用途。

    学好树,能够为我们提供一些新的解决问题的思路,因此十分重要。

 

 

   下面提供一段对于存储在二叉树的固定表达式的求解。由于时间仓促,还没来得及写将普通的表达式中缀式转换为普通的二叉树(不含括号),我会慢慢完善的。将这个树完善为一个通用的能计算表达式的二叉树。

    现行的表达式为:2+10*5-20/2

    要计算这个表达式,我用了数据结构中的栈,用来储存数。

    分为四个类:树的节点类、主函数类、栈接口类、栈接口实现类。

 

    树的节点类

 

public class TreeNode {
	//定义数据域
	private Object obj;
	//指向左孩子
    private TreeNode lChild;
    //定义右孩子
    private TreeNode rChild;
    
    //传入要构造的数据
    public TreeNode(Object obj){
    	this.obj = obj;
    }
    
    //修改数据域
    public void setObj(Object obj){
    	this.obj = obj;
    }
    
    //得到数据
    public Object getObj(){
    	return obj;
    }
    //设置左孩子
    public void setLChild(TreeNode lChild){
    	this.lChild = lChild;
    }
    //得到左孩子
    public TreeNode getLChild(){
    	return lChild;
    }
    //设置右孩子
    public void setRChild(TreeNode rChild){
    	this.rChild = rChild;
    }
    //得到右孩子
    public TreeNode getRChild(){
    	return rChild;
    }
    
    

}
 

 

     主函数类。说实话,这里写的并不是那么好。一方面没有实现中缀表达式转化为二叉树,而采用了直接创立树的节点的方法;另一方面违背了面向对象的思想,一团乱麻。

public class BTreeTest {

	private static TreeNode root;
	private static Stack OPND = new Stack();

	public static void main(String[] args) {
		BTreeTest test = new BTreeTest();
		test.buildBTree();
		test.midOrder(root);
		test.posOrder(root);
		if (OPND.lengthGet() == 1) {
		System.out.println("=" + OPND.delete());
		}

	}

	/**
	 * 建立二叉树
	 */
	private void buildBTree() {
		TreeNode node1 = new TreeNode('-');
		TreeNode node2 = new TreeNode('+');
		TreeNode node3 = new TreeNode('/');
		TreeNode node4 = new TreeNode(2);
		TreeNode node5 = new TreeNode('*');
		TreeNode node6 = new TreeNode(20);
		TreeNode node7 = new TreeNode(2);
		TreeNode node8 = new TreeNode(10);
		TreeNode node9 = new TreeNode(5);
		root = node1;
		node1.setLChild(node2);
		node1.setRChild(node3);
		node2.setLChild(node4);
		node2.setRChild(node5);
		node3.setLChild(node6);
		node3.setRChild(node7);
		node5.setLChild(node8);
		node5.setRChild(node9);
	}

	/**
	 * 中序遍历二叉树,得到输入的表达式
	 */
	public void midOrder(TreeNode root){
		//root为空,则自然地跳出这次递归;root不为空,则继续递归
		if(root != null){
			midOrder(root.getLChild());
			System.out.print(root.getObj());
			midOrder(root.getRChild());
		}
	}
	
	
	/**
	 * 后序遍历二叉树,得到逆波兰式,同时用栈计算出值
	 * @param root根
	 */
	public void posOrder(TreeNode root) {
		int a,b;
		if (root != null) {
			posOrder(root.getLChild());
			posOrder(root.getRChild());
			//判断是加法还是减法,还是操作数
			if (root.getObj().equals('+')) {
				 OPND.add(OPND.delete() + OPND.delete());
			} else if (root.getObj().equals('-')) {
				//因为减法和除法的两个操作数有先后顺序,所以不能够将操作数按取出的顺序操作,而应该相反
				a = OPND.delete();
				b = OPND.delete();
				OPND.add((b-a));
			} else if (root.getObj().equals('*')) {
				 OPND.add(OPND.delete() * OPND.delete());
			} else if (root.getObj().equals('/')) {
				a = OPND.delete();
				b = OPND.delete();
				OPND.add((b/a));
			} else {
				// 这样能够保留Object这个通用接口,成功地将Object类中的int转换成整数
				int num = Integer.parseInt(root.getObj().toString());
				OPND.add(num);
			}
		}
	}
}

 

栈接口

 

package LinkBinaryTree2;

public interface StackInterface {
	//往栈中添加一个元素
	void add(int e);
	//删除一个元素
	int delete();
	//判断栈是否为空
	boolean isEmpty();
	//求得栈的长度
	int lengthGet();
    //清空栈
	void initStack();
}

 

栈的实现:由于知识有限,没有设计成为泛型也是遗憾吧

import java.util.Arrays;

public class Stack implements StackInterface {

	/**
	 * 往栈中添加一个元素
	 */
	public void add(int e) {
		int[] temp = new int[++topOfStack];
		temp = Arrays.copyOf(stack, topOfStack);
		temp[topOfStack - 1] = e;
		stack = temp;
	}

	/**
	 * 删除一个元素
	 */
	public int delete() {
		int reElem = (int) stack[topOfStack - 1];
		topOfStack--;
		return reElem;
	}

	/**
	 * 判断栈是否为空
	 */
	public boolean isEmpty() {
		if (topOfStack == 0)
			return true;
		else
			return false;
	}

	/**
	 * 获得栈的长度
	 */
	public int lengthGet() {
		return topOfStack;
	}

	/**
	 * 清空栈
	 */
	public void initStack() {
		topOfStack = 0;
	}

	private int[] stack = new int[0];
	private int topOfStack=0;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值