线索化二叉树的处理笔记

26 篇文章 3 订阅

参考书籍:《算法4》。学习视频:尚硅谷Java数据结构与java算法(Java数据结构与算法)_哔哩哔哩_bilibili

线索化二叉树出现的原因: 希望充分利用各个结点的左右指针,让各个结点可以指向自己的前后结点。

线索化二叉树的基本介绍 :

  1. n个结点的二叉链表中含有n+1 公式 2n-(n-1)=n+1个空指针域。利用二叉链表中的空指针域。存放指向该结点的在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为“线索”
  2. 这种加上了线索的二叉链表称为线索链表相应的二叉树称为线索二叉树。根据线索性质的不同,线索二叉树可分为前序线索二叉树中序线索二叉树后序线索二叉树三种。
  3. 一个结点的前一个结点,称为前驱结点
  4. 一个结点的后一个结点,称为后继结点

将数列{1,3,6,8,10,14}构建成一颗二叉树,n+1=7;        

  

 代码实现

线索化二叉树后,Node结点的属性left和right,有两种情况:

  1. left指向的就是左子树,也可能是指向前驱结点,比如1结点的left指向的左子树,而10结点的left指向的就是前驱结点
  2. right指向的是右子树,也可能是后继结点,比如1节点right指向的是右子树,而10结点的right指向的是后继结点

中序遍历去处理 {8,3,10,1,14,6}

 

public class threadedbinarytreedemo {

	public static void main(String[] args)
	{
		//测试中序线索二叉树
	HeroNode root=	new HeroNode(1,"aa");
	HeroNode node2=	new HeroNode(3,"bb");	
	HeroNode node3=	new HeroNode(6,"cc");
	HeroNode node4=	new HeroNode(8,"dd");	
	HeroNode node5=	new HeroNode(10,"ff");
	HeroNode node6=	new HeroNode(14,"gg");
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
//测试中序线索化
threadedBinaryTree   a=new threadedBinaryTree();
a.setRoot(root);
a.threadedNodes();
	//测试	:以10号结点测试
  HeroNode leftNode=node5.getLeft();
//如果10号结点有左指针,说明线索化成功
  System.out.println("前驱结点是:"+leftNode);
  HeroNode rightNode=node5.getRight();
  System.out.println("10号结点的后继结点是:"+rightNode);
	}
}
//创建threadedBinaryTree二叉树——实现线索化功能
class threadedBinaryTree{
private HeroNode root;//最重要的是有根节点,进行遍历	
//为了实现线索化,需要创建一个指向当前结点的前驱结点的指针
//在递归进行线索化时,pre总是保留前驱结点,要不然我们的1号和14号结点的关系很难处理滴!
private HeroNode pre=null;	
public void setRoot(HeroNode root) {
	this.root = root;
}
//重载threadedNodes方法
public void threadedNodes()
{
	this.threadedNodes(root);
}

//编写对二叉树进行中序线索化的方法
public void threadedNodes(HeroNode node)
{
	//如果为空,直接返回
	if(node==null)
	{
		return ;
	}
	//先线索化左子树
	threadedNodes(node.getLeft());
	//线索化当前结点(很难理解,尽量多处理几遍)
	 
	//处理当前结点的前驱结点
	if(node.getLeft()==null)
	{
		//让当前结点的左指针指向前驱结点
		node.setLeft(pre);
		//修改当前结点的左指针的类型
		node.setlefttype(1);//指向前驱结点
	}
	//处理后继结点
	if(pre!=null&&pre.getRight()==null)
	{
		//让前驱结点的右指针指向当前结点
		pre.setRight(node);
		//修改前驱结点的右指针类型
		pre.setrighttype(1);
	}
	pre=node;//每处理一个结点后,当前结点变为下一个处理的前驱结点
	//线索化右子树
	threadedNodes(node.getRight());
		
}

}
//创建HeroNode结点
class HeroNode{
	  private int no;
	  private String name;
	  private HeroNode left;//默认null
	  private HeroNode right;//默认null
	  //规定一下以便于区分,如果lefttype=0,则表示左指针指向左子树,如果是1则代表指向前驱结点
	  //同理如果righttype=0,则表示指向右子树,如果是1则表示指向后继结点
	  private int lefttype;
	  private int righttype;
	  
	  public void setlefttype(int lefttype)
	  {
		  this.lefttype=lefttype;
	  }
	  public void setrighttype(int righttype)
	  {
		  this.righttype=righttype;
	  }
	  public HeroNode(int no,String name)
	  {
		  this.setNo(no);
		  this.setName(name);
		  
	  }
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getNo() {
		return no; 
	}
	public void setNo(int no) {
		this.no = no;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	 public String toString()
	 {
		 return "Hero[no="+no+",name="+name+"]";
	 }
	public int getLefttype() {
		return lefttype;
	}
	public int getRighttype() {
		return righttype;
	}
}

遍历线索化二叉树 

线索化后各个结点的指向都由变化,原来的遍历方式不能使用,需要线型方式遍历

public class threadedbinarytreedemo {

	public static void main(String[] args)
	{
		//测试中序线索二叉树
	HeroNode root=	new HeroNode(1,"aa");
	HeroNode node2=	new HeroNode(3,"bb");	
	HeroNode node3=	new HeroNode(6,"cc");
	HeroNode node4=	new HeroNode(8,"dd");	
	HeroNode node5=	new HeroNode(10,"ff");
	HeroNode node6=	new HeroNode(14,"gg");
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
//测试中序线索化
threadedBinaryTree   a=new threadedBinaryTree();
a.setRoot(root);
a.threadedNodes();
	//测试	:以10号结点测试
  HeroNode leftNode=node5.getLeft();
//如果10号结点有左指针,说明线索化成功
  System.out.println("前驱结点是:"+leftNode);
  HeroNode rightNode=node5.getRight();
  System.out.println("10号结点的后继结点是:"+rightNode);
  System.out.println("使用线索化遍历二叉树");
  a.threadedList();//8,3,10,1,14,6
  }
}
//创建threadedBinaryTree二叉树——实现线索化功能
class threadedBinaryTree{
private HeroNode root;//最重要的是有根节点,进行遍历	
//为了实现线索化,需要创建一个指向当前结点的前驱结点的指针
//在递归进行线索化时,pre总是保留前驱结点,要不然我们的1号和14号结点的关系很难处理滴!
private HeroNode pre=null;	
public void setRoot(HeroNode root) {
	this.root = root;
}
//重载threadedNodes方法
public void threadedNodes()
{
	this.threadedNodes(root);
}

//编写遍历线索化二叉树的方法
public void threadedList()
{//定义一个变量,存储当前遍历的结点,从root开始
	HeroNode node=root;
	while(node!=null)
	{
		 //循环的找lefttype=1的结点,第一个找到的是8结点
		//后面随着遍历而变化,因为当lefttype==1的时候,该结点是按照线索化
		while(node.getLefttype()==0)
		{
			node=node.getLeft();//遍历去处理
		}
		//打印当前这个结点
		System.out.println(node);
		//如果当前结点的右指针指向的是后继结点,就一直输出
		while(node.getRighttype()==1)
		{
			//获取到后继结点
			node=node.getRight();
			System.out.println(node);
			
		}
		//替换这个遍历的结点
		node=node.getRight();
	
	}

}

//编写对二叉树进行中序线索化的方法
public void threadedNodes(HeroNode node)
{
	//如果为空,直接返回
	if(node==null)
	{
		return ;
	}
	//先线索化左子树
	threadedNodes(node.getLeft());
	//线索化当前结点(很难理解,尽量多处理几遍)
	 
	//处理当前结点的前驱结点
	if(node.getLeft()==null)
	{
		//让当前结点的左指针指向前驱结点
		node.setLeft(pre);
		//修改当前结点的左指针的类型
		node.setlefttype(1);//指向前驱结点
	}
	//处理后继结点
	if(pre!=null&&pre.getRight()==null)
	{
		//让前驱结点的右指针指向当前结点
		pre.setRight(node);
		//修改前驱结点的右指针类型
		pre.setrighttype(1);
	}
	pre=node;//每处理一个结点后,当前结点变为下一个处理的前驱结点
	//线索化右子树
	threadedNodes(node.getRight());
		
}

}
//创建HeroNode结点
class HeroNode{
	  private int no;
	  private String name;
	  private HeroNode left;//默认null
	  private HeroNode right;//默认null
	  //规定一下以便于区分,如果lefttype=0,则表示左指针指向左子树,如果是1则代表指向前驱结点
	  //同理如果righttype=0,则表示指向右子树,如果是1则表示指向后继结点
	  private int lefttype;
	  private int righttype;
	  
	  public void setlefttype(int lefttype)
	  {
		  this.lefttype=lefttype;
	  }
	  public void setrighttype(int righttype)
	  {
		  this.righttype=righttype;
	  }
	  public HeroNode(int no,String name)
	  {
		  this.setNo(no);
		  this.setName(name);
		  
	  }
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getNo() {
		return no; 
	}
	public void setNo(int no) {
		this.no = no;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	 public String toString()
	 {
		 return "Hero[no="+no+",name="+name+"]";
	 }
	public int getLefttype() {
		return lefttype;
	}
	public int getRighttype() {
		return righttype;
	}
	
}

学习如逆水行舟,不进则退。和小吴一起加油吧! 

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小吴有想法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值