从创建二叉树到线索二叉树的遍历

我们今天来看一下从创建到线索二叉树,从创建到线索化,到遍历。

 

这就是我们今天要研究的二叉树!

我们来看看每个节点的构成:

每个节点由五个域组成,分别是左标记,左节点,data域,右节点,右标记。

接下来我们来看看创建二叉树的方法:(这里我们是用先序创建的,当然中序创建和后续创建也非常类似):

 

 

	//当前树先序遍历的结果
	private char[] relation= {'A','B','D','^','G','^','^','^','C','E','^','H','^','^','F','^','^'};
	
	
	private static int flag=0;//遍历数组的index
	
	private TreeNode pre=null;//记录当前节点的前驱
	
	
	/**
	 * 这里我们创建一个先序遍历的二叉树
	 * @param root
	 */
	public void first_create(TreeNode root) {
		
		//如果当前值为‘^’则表示为空,我们需要设置当前节点的值域为空,并且让flag前移(因为flag当前值已经赋值给了root的data域)
		if(relation[flag]=='^') {
			root.setData('^');
			flag++;
		}
		else {
//			System.out.println(relation[flag]);
			
			//创建左节点
			TreeNode node1=new TreeNode();
			//创建右节点
			TreeNode node2=new TreeNode();
			
			//给当前节点的data域赋值
			root.setData(relation[flag++]);
			
			//递归调用(先左后右)
			root.setLnode(node1);
			first_create(node1);
			
			root.setRnode(node2);
			first_create(node2);
			
		}
	}

这里注意了,我们对二叉树的线索化可以有多种手段

1.我们可以在创建二叉树的同时对其进行线索话(效率较高)

2.我们可以在创建二叉树后通过遍历二叉树的过程中对其进行线索化(易于理解)

 

当然,还有其它的线索化方法,其实都是异曲同工!

 

 

接下来,我们对其进行线索话(注意,我们这里是通过中序遍历二叉树对其实现线索化)

	/**
	 * 我们通过中序遍历的方式来使上面的普通二叉树成为线索二叉树
	 * @param root
	 */
	public void center_travel(TreeNode root) {
		
		if(root.getData()=='^') {
			return;
		}
		
		//递归遍历左枝
		center_travel(root.getLnode());
		
//*********************************************通过中序遍历将二叉树线索话的过程********************************************//		
		//如果当前节点的左指针域的data为'^'则代表当前点的左枝已经为空,所以将root的左指针域设置为pre(记录其前驱节点),
		//并且设置lflag为1(表示当前节点的左指针域包含的是其前驱)
		if(root.getLnode().getData()=='^') {
//			System.out.println(root.getData()+"************");
			root.setLflag(1);
			root.setLnode(pre);				
		}
		
		//pre!=null是为了排除当前节点是哦根节点的可能(根节点没有前驱)
		if(pre!=null&&pre.getRnode().getData()=='^') {
//			System.out.println(root.getData()+"############");
			pre.setRflag(1);
			pre.setRnode(root);
		}
		//记录上一次访问的节点
		pre=root;
//*******************************************************************************************************************//
		//递归遍历右支
		center_travel(root.getRnode());
		
	}

 

线索化后我们涉及到找某个节点的前驱节点和后继节点的问题。

 

前驱节点:当前节点的前驱节点就是当前节点对应的左子树二叉树中序遍历的最后一个节点。

	/**
	 * 寻找目标节点的前驱节点
	 * @param root
	 * @return
	 * 因为该线索二叉树为中序遍历的线索二叉树,所以当前节点的前驱节点就是当前节点对应的左子树(中序遍历)最后一个访问的节点
	 */
	public TreeNode find_pre(TreeNode root) {
		
		 TreeNode pre = null;//记录前驱节点

		 if(root.getLflag()==1) {//当前节点无左子树,左子树中记录的就是前驱节点,直接获取
			 return root.getLnode();
		 }
		 else {//当前节点有左子树,我们寻找其最后一个访问的节点
		 for(root=root.getLnode();root.getRflag()==0;root=root.getRnode());
		 	return root;
		 }
	}

后继节点:当前节点的后继节点就是当前节点对应的右子树中第一个访问的节点。

	/**
	 * 寻找后继节点
	 * 
	 * 因为该线索二叉树为中序遍历,所以当前节点的后继节点就是其对应的右子树中第一个访问的节点
	 */
	
	public TreeNode find_after(TreeNode root) {
		
		 //与寻找前驱节点同理
		
		 TreeNode pre = null;
		 if(root.getRflag()==1) {
			 return root.getRnode();
		 }
		 else {
		 for(root=root.getRnode();root!=null&&root.getLflag()==0;root=root.getLnode());
		 	return root;
		 }
	}

接下来的我们来看看遍历线索二叉树的代码,当然,线索二叉树的遍历有多种方式,我们在这里只介绍通过后继节点遍历:

 

在遍历之前,我们需要先找到中序遍历二叉树所访问的第一个节点。因为只有得到第一个节点,然后找一直找后继节点,就可以完整的遍历一颗线索二叉树

 

寻找第一个访问的节点

	/**
	 * 寻找第一个节点
	 * @param root
	 * @return
	 * 中序遍历二叉树的第一个节点为最左边的元素
	 */
	public TreeNode find_first(TreeNode root) {
		
		TreeNode p=root;//避免改变root(root一旦被改变,我们将失去这棵树的根,也就相当于失去了这棵树)
		
		if(p==null) {//如果树为空。直接返回null
			return null;
		}else {
			while(p.getLflag()==0) {//一直向左寻找,直到寻找到叶子节点
				p=p.getLnode();
			}
			return p;
		}
	}

遍历二叉树

 

	/**
	 *遍历线索二叉树(根据找后继节点的方式)
	 *
	 *
	 *1.我们需要先找到首个访问的节点(使用上面的firstroot方法)
	 *2.根据每次传入的节点,我们通过findafter方法来访问其后继节点;
	 *
	 */
	
	public void travel_tree(TreeNode root) {
		
		TreeNode firstroot=find_first(root);//找到中序遍历访问的第一个节点
		
		while(firstroot!=null) {
			System.out.println(firstroot.getData());//访问节点
			firstroot=find_after(firstroot);//寻找当前节点的下一个节点
		}
	}

只需要再写一个Test方法就可以测试代码的运行情况了!谢谢观赏!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值