1.基本概念
遍历二叉树实质上是对一个非线性结构进行线性化操作,使每一个结点在这些线性序列中有且仅有一个前驱和后继,当以二叉链表作为存储结构时,只能找到结点的左、右结点信息,而不能直接得到结点在任一序列中的前驱和后级信息,为此引入线索二叉树来保存这些在动态过程中得到的有关前驱和后继的信息。假设 以下序列为某个二叉树的中序遍历 " ANDFG” ,其中N的前驱是‘A’,后继是‘D’;
进行构造线索二叉树时,若结点有左子树,其中lchild 指向左孩子,否则令lchirld指向其前驱;
若结点有右子树,其中 rchild 指向右孩子,否则令 rchild指向其后继。其中指向前驱和后继的结点也叫线索。
其中 LTag={ 0 lchild指向结点的左孩子
1 lchild指向结点的前驱}
RTag = { 0 rchild指向结点的右孩子
1 rchild质量结点的后继}
二叉树的二叉树线索类型定义如下:
typedef struct Bithrnode
{
TElemType data;
struct Bithrnode *lchild,*rchild; //左右孩子指针
int LTag,RTag; //左右是否有为空的标志
} Bithrnode,*Bithrtree;
2.构造线索二叉树:
线索二叉树的构造实质是将二叉链表中的空指针改为指向前驱和后继的线索,而前驱或后继的信息只有在遍历时才能得到,因此线索化的过程即在遍历的过程中修改空指针的过程。根据二叉树遍历方式不同,可以得到中序线索二叉树,先序线索二叉树,后序线索二叉树。
以结点p为根的子树中序线索化
(1)如果p非空,左子树递归线索化;
(2)如果p的左孩子为空,则给p加上左线索,将LTag置为1,让p的左孩子指针指向前驱pre,否则将p的LTag置为0;
(3)如果pre的右孩子为空,则给pre加上右线索,将RTag置为1,让pre的右孩子指针指向后继p,否则将RTag置为0;
(4)将pre指向刚访问过的结点p,即pre=p;
(5)右子树递归线索化。
算法描述:
void Inthreading(Bithrtree p)
{
if(p)
{
Inthreading(p->lchild); //左子树线索化
if(!p->lchild) //p的左孩子为空则指向前驱pre
{
p->LTag=1; //给p加上左线索
p->lchild=pre;
}
else p->LTag=0;
//就好比“ANDFG”其中 N的前驱为A,那么A的后继为N
if(!pre->rchild) //pre的右孩子为空指向后继p
{
pre->RTag=1; //给pre加上右线索
pre->rchild=p;
}
else p->RTag=0;
pre=p;
Inthreading(p->rchild); //右子树线索化
}
}
3.遍历线索二叉树
A.在中序线索二叉树中查找
(1)查找p指针所指结点的前驱
若p->LTag=1,则p的左链指向其前驱;
若p->LTag=0,则说明p有左子树,结点的前驱是遍历左子树时最后访问的一个结点;
(2)查找p指针所指的后继结点
若p->RTag=1,则p的右链指向其后继;
若p->RTag=0,则说明p有右子树,结点的后继是遍历其右子树时访问的第一个结点,即右子树中最左下的结点。
B.在先序线索二叉树中查找:
(1)查找p指针所指结点的前驱
若p->LTag=1,则p的左链指向其前驱;
若p->LTag=0,则说明p有左子树,此时p的前驱有两种情况,若p是双亲的左孩子,则其前驱为其双亲结点;否则是其双亲的左子树上先序遍历最后访问的结点;
(2)查找p指针所指的后继结点
若p->RTag=1,则p的右链指向其后继;
若p->RTag=0,则说明p有右子树,p的后继必然为其左子树根(若存在)或右子树根。
C. 后序线索二叉树中查找:
(1)查找p指针所指结点的前驱
若p->LTag=1,则p的左链指向其前驱;
若p->LTag=0,当p->RTag=0时,p的右链指向其前驱;若p->LTag=0,p->RTag=1时,p的左链指向其前驱;
(2)查找p指针所指的后继结点
若p是二叉树的根,则其后继为NULL;
若p是双亲的右孩子,则其后继为双亲结点;
若p是其双亲的左孩子,则p没有右兄弟,其后继为双亲结点;
若p是其双亲的左孩子,且p有右兄弟,则其后继为双亲的右子树上按后序遍历列出的第一个结点。
遍历中序线索二叉树:
void Inordertraverse(Bithrtree T)
{
p=T->lchild; //p指向根结点
while(p!=T)
{
while(p->LTag==0) p=p->lchild; //左子树
printf("%d ",p->data);
while(p->RTag==1&&p->rchild!=T) //沿右线索访问后继结点
{
p=p->rchild;
printf("%d ",p->data);
}
p=p->rchild; //右子树
}
}