package trees;
//线索二叉树
public class BiThrTree {
static final class ThrNode{
Integer data;
ThrNode left; //左孩子
ThrNode right; //右孩子
int LTag; //标记 1表示左孩子为前驱
int RTag; //标记 1表示右孩子为后继
ThrNode(Integer data){
this.data = data;
LTag = 0;
RTag = 0;
}
ThrNode(){
this(null);
}
public String toString(){
return data+"";
}
}
ThrNode root; //根结点
ThrNode Thrt; //头结点
ThrNode pre=null;//用来记录前一个访问的结点
//以结点p为根结点的子树中序线索化
public void inThreading(ThrNode p){
if(p!=null){
inThreading(p.left); //递归线索化左子树
if(p.left==null){ //设置结点的前驱线索,p的前驱为pre
p.LTag = 1;
p.left = pre;
}
else{ //如果p有左孩子
p.LTag = 0;
}
if(pre != null){ //设置pre结点的后继线索,pre的后继为p
if( pre.right == null){
pre.RTag = 1;
pre.right = p; //pre的后继设为p
}
else{
pre.RTag = 0;
}
}
pre = p; //将p设置为前一个访问的结点
inThreading(p.right); //线索化p的右子树
}
}
/*
* ???
* 给二叉树设置一个头结点,然后将第一个结点的前驱设置为头结点,头结点的后继设置为最后一个结点
* 最后一个结点的后继设置为头结点,就既可以实现从第一个结点顺后继,也可以从最后一个结点顺前驱遍历
*/
//带头结点的二叉树中序线索化
public void inOrderThreading(){
Thrt = new ThrNode(); //构造头结点
Thrt.LTag = 0; //头结点左孩子为树根(树非空)
Thrt.RTag = 1; //头结点右孩子为线索
Thrt.right = Thrt; //初始化时右线索指向自己,
if(root == null){
Thrt.left = root; //树为空时左孩子也指向自己
}
else{
Thrt.left = root; //左孩子指向树根
pre = Thrt; //pre指向头结点
inThreading(root); //将树线索化
Thrt.right = pre; //此时pre指向最后一个访问的结点,将头结点的右孩子指向最后一个结点
pre.right = Thrt; //将最后一个结点的右孩子指向头结点
pre.RTag = 1; //
}
}
/*
* 遍历中序线索二叉树
* 对于一个结点p,如果p.RTag=1,则其后继为p.right,
* 如果p.RTag=0,那么由中序遍历的规律可以知道它的后继为其右子树的最左下的结点。
* 对于二叉线索树,它的所有叶子结点的左右孩子都是指向其前驱和后继的,不会有为空的情况
*/
void inOrderTraverse(ThrNode thrt){
if(thrt != null){ //头结点不为空
ThrNode p = thrt.left; //指向树根
while(p != thrt){ //树不为空,或者遍历结束
while(p.left!=null) p = p.left; //找到以p为根时第一个访问的结点,即最左下的结点
System.out.print(p);
//一直找后继结点并输出
while(p.RTag==1 && p.right != thrt){
p = p.right;System.out.print(p);
}
//如果没有后继,那么它的后继是右子树的最左下结点,即把p的右子树当做一颗树继续遍历
p = p.right;
}
}
}
}