8.5线索二叉树
8.5.1基本概念
每个结点增加两个指针域,指示遍历时得到的前驱和后继。
但是,存储密度大大降低。
在n个结点的二叉链表中必定存在有n+1个空链域,
利用空链域来存放结点的前驱、后继信息。
同时结点增加两个标志域LTag,RTag:
若LTag=0,LChild域指向左孩子;
若LTag=1,LChild域指向其前驱。
若RTag=0,RChild域指向右孩子;
若RTag=1,RChild域指向其后继。
当二叉树以某种次序遍历
使其变为线索二叉树的过程
叫做线索化,
指向结点前驱和后继的指针,称为线索。
结点定义:
typedef struct BiThrNode{
int data;
int Ltag, Rtag;
struct node *lchild, *rchild;
} BiThrNode,* BiThrTree;
8.5.2先序线索二叉树
结点x的后继:
Rtag=1:
Rchild指示其后继;
Rtag=0:
A)若x有左孩子,后继为其左孩子;
B)若x无左孩子有右孩子,后继为其右孩子。
例:
先序序列:ABCDE
8.5.3中序线索二叉树
结点x的后继:
Rtag=0://有右孩子,根据左根右的顺序,先访问最左的子孙
其后继为中序遍历其右子树时第一个被访问的结点,即其右子树最左下的结点。
Rtag=1:
Rchild指示其后继;
中序序列:BCAED
在中序线索二叉树中
查找p的后继结点,并用succ指针返回结果
//此代码用于左右孩子和左右tag域 皆已经确定,即已经完成线索化的
void InSucc(BiTNode * p,BiTNode * succ){
if(p->Rtag==1) succ=p-> RChild;
else{ /* 在p的右子树中查找最左下的结点*/
q=p->RChild;
while(q->Ltag==0) q=q->LChild;
succ=q;
}
}
在中序线索二叉树中
查找p的前驱结点,并用pre指针返回结果
//此代码用于左右孩子和左右tag域 皆已经确定,即已经完成线索化的
void InPre(BiTNode * p,BiTNode * pre){
if(p->Ltag==1)//p结点没有左孩子
pre=p->LChild;//因为没有左孩子的结点左孩子存放的就是则p的前驱
else{ /* 在p的左子树中查找最右下的结点*/
q=p->LChild;
while(q->Rtag==0) q=q->RChild;
pre=q;
}
}
8.5.4后序线索二叉树
后序序列:CBEDA
结点x的后继:
Rtag=1:Rchild指示其后继;
Rtag=0:
A)若x为根,无后继;
B)若x为其双亲的右孩子或为其双亲的左孩子且其双亲无右子树,其后继即为双亲结点;
C)若x为其双亲的左孩子且其双亲有右子树,其后继为遍历其双亲右子树时第一个被访问的结点,即其双亲右子树最左下的结点。
8.5.5带头结点的线索二叉树
头结点的:
ltag=0, lchild指向根结点 ,
rtag=1, rchild指向遍历序列中最后一个结点 。
遍历序列中第一个结点的lchild域指向头结点 ,
遍历序列中最后一个结点的rchild域指向头结点。
8.5.5.1带头结点的中序线索二叉树
中序序列:BCAED
//中序遍历的线索化
NODE * inthread(NODE * bt){//bt是根节点
t=(NODE *)malloc(sizeof(NODE));//t是头结点
t->ltag=0; t->rtag=1; t->rchild=t;//现在还不知道遍历的最后一个节点是哪个,t的右孩子暂时指向自己
if(!bt) t->lchild=t;//空树
else {
pre=t; t->lchild=bt;
inthreading(bt);
//线索化完了之后
pre->rtag=1; pre->rchild=t;//遍历序列中最后一个结点的rchild域指向头结点。
t->rchild=pre;//t的右孩子可以确定了,为当前的pre结点
}
return t;
}
//线索化的过程
void inthreading( NODE * p ) {
if( p ) {
inthreading( p->lchild );
if( !p->lchild )//没有左孩子
{ p->ltag=1; p->lchild=pre; }
if( !pre->rchild )
{ pre->rtag=1; pre->rchild=p; }
pre=p;
inthreading( p->rchild );
}
}
//对已经线索化的树进行中序遍历,并输出中序遍历结果
void Inorder_Thr( NODE *t )//t是该树的头结点
{
p=t->lchild;
while( p!=t )
{
while( p->ltag==0 ) p=p->lchild;
printf(p->data );
while( p->rtag==1 && p->rchild!=t )
{ p=p->rchild; printf(p->data ); }
p=p->rchild;
}
}
例题:
下列线索二叉树中(用虚线表示线索)符合后序线索树定义的是______。
答案:D