五、线索二叉树
当以二叉链表作为存储结构时,只能找到结点的左、右孩子信息,而不能直接得到结点在任一序列中的前驱和后继信息,
这种信息只有在遍历的动态过程中才能得到。
线索二叉树结点结构
规定:
若结点有左子树,则其LChild域指向其左孩子,否则LChild域指向其前驱结点;
若结点有右子树,则其RChild域指向其右孩子,否则RChild域指向其后继结点。
其中:
LTag:
0----LChild域指向结点的左孩子
1----LChild域指向结点的遍历前驱
RTag:
0----RChild域指向结点的右孩子
1----RChild域指向结点的遍历后继
在这种存储结构中,指向前驱和后继的结点的指针称为线索。以这种结构组成的二叉链表作为二叉树的的存储结构,
称为线索链表。对二叉树以某种次序进行遍历并且加上线索的过程称为线索化。线索化了的二叉树称为线索二叉树。
实质:
将二叉链表中的空指针域上填上相应结点的遍历前驱或遍历后继结点的地址,而前驱和后继的地址只能在动态的
遍历过程中才能得到,因此线索化的过程即为在遍历过程中修改空指针域的过程。
建立中序线索树:
(1)算法思想:
设置一个指针pre,始终记录刚访问过的结点。
如果当前遍历结点root的左子域为空,则让左子域指向pre;
如果前驱pre的右子域为空,则让右子域指向当前遍历结点root;
为下次做准备,当前访问结点root作为下一个访问结点的前驱pre。
(2)算法描述:
void Inthread(BiTree root)
{
if(root != NULL)
{
Inthread(root->LChild); //线索化左子树
if(root->LChild == NULL)
{
root->LTag = 1;
root->LChild = pre;
}
if(pre != NULL && root->RChild == NULL)
{
pre->RChild = root;
pre->RTag = 1;
}
pre = root; //当前访问结点为下一个访问结点的前驱
Inthread(root->RChild); //线索化右子树
}
}
在线索二叉树中找前驱结点
(1)算法思想
对于结点p,当p->LTag = 1时,p->LChild指向p的前驱;当p->LTag = 1时,p->LChild指向p的左孩子。
作为根p的前驱结点,它是中序遍历p的左子树时访问的最后一个结点,即左子树的“最右下端”结点。
(2)算法描述
BiTNode* InPre(BiTNode* p)
{
if(p->LTag == 1)
{
pre = p->LChild;
}
else
{
for(q = p->LChild;q->RTag == 0;q = q->RChild)
{
pre = q;
}
}
return pre;
}
在线索二叉树中找后继结点
(1)算法思想
对于结点p,若p->RTag = 1时,p->RChild即为p的后继结点;当p->RTag = 0时,说明p有右子树,
此时p的中序遍历后继结点为其右子树的“最左下端”的结点。
(2)算法描述
BiTNode* InNext(BiTNode *p)
{
if(p->RTag == 1)
{
next = p->RChild;
}
else
{
for(q = p->RChild;q->LTag == 0;q = q->LChild)
{
next = q;
}
}
return next;
}
遍历中序线索树
(1)算法思想
求出某种遍历次序下第一个被访问结点;
然后连续求出刚访问结点的后继结点,直至所有的结点均被访问。
(2)算法描述
BiTNode* InFirst(BiTree bt)
{
BiTNode *p = bt;
if(p =- NULL)
{
return NULL;
}
while(p->LTag == 0)
{
p = p->LChild;
}
return p;
}
void TInOrder(BiTree bt)
{
BiTNode * p;
p = InFirst(bt);
while(p != NULL)
{
visit(p);
p = InNext(p);
}
}