java实现二叉树

1.二叉树的主要性质

性质1:非空二叉树上叶子节点数等于双分支节点数加1。(使用总分支数=总节点数-1证明)

性质2:二叉树的第i层上最多有2^(i-1)个节点(i>=1)。

性质3:高度为k的二叉树最多有2^(i-1)个节点。

性质4:高度为k的二叉树最多有2^k-1个节点。

2.二叉树的存储结构

(1)顺序存储结构:就是采用数组来存储一个二叉树。

(2)链式存储结构:就是采用链表来存储一个二叉树。

3.二叉树的遍历

(1)先序遍历:根左右。

(2)中序遍历:左根右。

(3)后序遍历:左右根。

(4)层序遍历:从上到下,从左到右,开始遍历。

4.二叉树的实现

               

二叉树节点的结构类:

class Node{
	private Object data =null;
	private Node lchild =null;
	private Node rchild =null;
	public Node(){}
	public Node(Object data) {
		super();
		this.data = data;
	}
	public Object getData() {
		return data;
	}
	public void setData(Object data) {
		this.data = data;
	}
	public Node getLchild() {
		return lchild;
	}
	public void setLchild(Node lchild) {
		this.lchild = lchild;
	}
	public Node getRchild() {
		return rchild;
	}
	public void setRchild(Node rchild) {
		this.rchild = rchild;
	}
}


使用输入的数组来构造二叉树:

思想:

首先将输入的数组数据转换成Node节点,并使用List存储。然后构造完了一堆节点,需要对节点之间建立关系。而关系可以根据自身定义,我的定义是输入数组中的数据下标为奇数做为左孩子节点,偶数为右孩子节点。然后对边界的定义如2*i+2,无论当总节点为偶数时,二叉树本身的结构是没有最右边的叶子节点的,也就是说此树非满二叉树,那么我们使用2*i+2来计算不存在的最右边叶子节点的右孩子节点时会报下标越界的异常。

实现:

/*构造树
	 * 使用数组构造二叉树
	 * 定义的规则:奇数作为左孩子,偶数的时候作为右孩子
	 * 
	 * */
	public static List<Node> createBt(Object[] objArr){
		List<Node> retList =new ArrayList<Node>();
		for(Object obj :objArr){
			retList.add(new Node(obj));
		}
		if(retList.size() !=0){
			for(int i=0;i<retList.size()/2;i++){
				//奇数情况下
				if(retList.get(2*i+1) !=null){
					retList.get(i).setLchild(retList.get(2*i+1));
				}
				//偶数情况下  
				if(2*i+2 <=retList.size()-1 && retList.get(2*i+2) !=null){
					retList.get(i).setRchild(retList.get(2*i+2));
				}
			}
		}
		return retList;
	}

构造的结果如前图所示。


先序遍历,递归方式遍历二叉树:

/* 先序遍历
	 * 根左右
	 * 递归方式
	 * */
	public static void preBtByRecursion(Node n){
		if(n !=null){
			System.out.println("值:"+n.getData());
			preBtByRecursion(n.getLchild());
			preBtByRecursion(n.getRchild());
		}else{
			return;
		}
	}


中序遍历,递归方式遍历二叉树:
       public static void orderBtByRecursion(Node n){
        if(n !=null){
            orderBtByRecursion(n.getLchild());
            System.out.println("值:"+n.getData());
            orderBtByRecursion(n.getRchild());
        }else{
            return;
        }
    }

后序遍历,递归方式遍历二叉树:

/* 后序遍历
	 * 左右根
	 * 递归方式
	 * */
	public static void postBtByRecursion(Node n){
		if(n !=null){
			postBtByRecursion(n.getLchild());
			postBtByRecursion(n.getRchild());
			System.out.println("值:"+n.getData());
		}else{
			return;
		}
	}


先序遍历,非递归方式遍历二叉树:
思想:

遍历二叉树采用当前遍历路径尽可能深的去遍历二叉树,如果当前路径走到了尽头就需要往回走,那么就需要回溯了。为了对之前走过的路径进行回溯,那么就需要使用一个辅助的结构来记录之前走过的节点。而我们从头到尾的存入遍历过的节点,然后从尾到头的弹出节点。这种结构恰好符合栈的结构。所以就采用辅助栈来存储遍历过的节点。从而达到回溯的目得。

实现:

/* 先序遍历
	 * 根左右
	 * 非递归方式
	 * */
	public static void preBt(List<Node> list){
		Stack<Node> stack =new Stack<Node>();
		Node root =list.get(0);
		while(root !=null || !stack.isEmpty()){
			System.out.println("值:"+root.getData());
			stack.push(root);
			root =root.getLchild();
			while(root ==null && !stack.isEmpty()){
				root =stack.pop();
				root =root.getRchild();
			}
		}
	}


中序遍历,非递归方式遍历二叉树:

思想:

和前面的前序遍历二叉树的思想差不多,都是采用辅助栈来实现回溯。

实现:

/* 中序遍历
	 * 左根右
	 * 非递归方式
	 * */
	public static void orderBt(List<Node> list){
		Stack<Node> stack =new Stack<Node>();
		Node n =list.get(0);
		while(n !=null || !stack.isEmpty()){
			stack.push(n);
			n =n.getLchild();
			while(n ==null && !stack.isEmpty()){
				n =stack.pop();
				System.out.println("值:"+n.getData());
				n =n.getRchild();
			}
		}
	}


后序遍历,非递归方式遍历二叉树:

思想:

采用双辅助栈的方式来实现遍历的。后序遍历是左右根,为了调整遍历出来的节点的顺序,其实除了树最顶上的节点作为根外,剩下的节点,对于孩子节点父节点,对于同层的点来说就是兄弟节点。所以剩下的点都可以当作左右节点来看待了。树最顶上的点在进行操作前,先将其存入栈s1中,在从栈s1中弹出存入栈s2中。(肯定有人会问,直接放入栈s2中不就完事了,这样做,当栈s1都没有根节点,那么它从哪开始遍历都不知道)。其他节点就是同样的套路了。压入栈s1的顺序左右,弹出栈的顺序是右左,在压入到栈s2的顺序是右左,那么弹出栈的顺序就是左右了,加上之前特殊处理的根在s2最底下,s2的整体顺序就是左右根,符合后序遍历的规则了。

实现:

/* 后序遍历
	 * 左右根
	 * 非递归方式
	 * */
	public static void postBt(List<Node> list){
		Stack<Node> stack1 =new Stack<Node>();
		Stack<Node> stack2 =new Stack<Node>();
		Node n =list.get(0);
		stack1.push(n);
		while(!stack1.isEmpty()){
			n =stack1.pop();
			stack2.push(n);
			if(n.getLchild() !=null){
				stack1.push(n.getLchild());
			}
			if(n.getRchild() !=null){
				stack1.push(n.getRchild());
			}
		}
		while (!stack2.isEmpty()) { 
                        System.out.println(stack2.pop().getData()); 
		} 
	}
测试:

        public static void main(String[] args) {
		String[] str ={"1","2","3","4","5","6"};
		List<Node> list =createBt(str);
		postBt(list);
	}
结果:



--------------------------------------------------------------

懒得在开博客了,就从这儿写写最近的感悟吧:

毕业之后,工作了大半年了,要存款没多少存款,要对象没对象,家庭条件凑合吧,没培养啥爱好,就涨了点java方面的见识。周围的同事平时都在聊买房,接娃等,我常常告诉自己,自己还有梦想。终有一天认为技术过硬一切都会有的吧。可能也许是在自欺欺人吧。想到这些就烦躁,不想了,继续活在自己的精神世界,但是不得不说最近写非递归的遍历二叉树有点费脑子啊。前面的话就当我这个孤独患者的自嘲吧。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值