在普通的二叉树中,我们不难通过遍历得到某种序列串——中序的,先序的,后序的,层次的,等等等等。
在构建线索树的过程,是很简单的,只需要判断pre节点的rchild有没有指向节点,当前lchild有没有指向节点,则把这些空余的指针指向合适的位置即可,思路和操作简单,不赘述。
但是对遍历线索二叉树,寻找前驱以及后继节点,利用中序二叉树寻找先序后继以及后序前驱需要其他操作。
1,寻找前驱,后继节点。
如果目标节点的rchild或lchild以线索指针的形式存在,那么后继/前驱会很简单,直接用rchild/lchild指去即可。
如果rchild或lchild以结构指针存在,那么p的后继就是rchild为根的子树的最左节点(LTag==1),同样道理,p的前驱就是lchild为根的子树的最右节点(可见post=p->rchild这一步和pre=p->lchild是公共的)。
代码如下:
int InitBiThrTree(BiThrTree &head,BiThrTree T) //链线索函数
{
head=(BiThrTree)malloc(sizeof(BiThreNode));
head->LTag=0;
head->RTag=1;
head->lchild=T;
head->rchild=head;
InThrTree(T);
pre->rchild=head;
pre->RTag=1;
head->rchild=pre;
return 1
}
void InThrTree(BiThrTree T)
{
if(T)
{
InThrTree(T->lchild);
if(!T->lchild)
{
T->LTag=0;
T->lchild=pre;
}
if(!pre->rchild)
{
pre->RTag=0;
pre->rchild=T;
}
pre=T;
InThrTree(T->rchild);
}
}
BiThrTree InPre(BiThrTree T,BiThrTree p) //先驱函数
{
BiThrTree temp;
temp=p->lchild;
if(p->LTag==0)
{
return temp; //次序指针有效
}
else{
while(temp->RTag==0){
temp=temp->rchild; //次序结点无效
}
return temp;
}
}
BiThrTree InPost(BiThrTree T,BiTHrTree p) //后继函数
{
BiThrTree temp;
temp=p->rchild;
if(p->RTag==0)
{
return temp; //次序指针有效
}
else{
while(temp->LTag==0){
temp=temp->lchild; //次序结点无效
}
return temp;
}
}
2,在以上基础的遍历/查询函数
void findNode(BiThrTree head,int x)
{
BiThrTree temp;
if(head->LTag==1){
temp=head->lchild;
while(temp->LTag==0&&temp!=head)
{
temp=temp->lchild;
}}
while(temp!=head&&temp->data!=x)
{
temp=InPost(temp);
}
if(p==head)
{
printf("There isn`t such a node of which the data is %d",x)
}
else{
printf("Positive");
}
}
}
void Treval(BiThrTree head)
{
BiThrTree temp=head->lchild;
while(temp!=head){
while(temp->LTag==0&&temp!=head)
{
temp=temp->lchild;
}
while(temp->RLag==0&&temp!=head)
{
temp=temp->rchild;
printf("%d",temp->data); //本质上和上面后继函数的思路一致
}
temp=temp->rchild;
}
}
3,利用中序线索求先序后继以及后序前驱
我们要把问题分成三部分
1,该节点是非叶子节点,存在左子树
那么lchild为后继
2,该节点是非叶子节点,不存在左子树
那么rchild为后继
3,如果该节点是叶子节点
那么后继是该叶子树根的数根的...(有树根就一直找下去)的右孩子
同样道理,
1,该节点是非叶子节点,存在右子树
那么rchild为前驱
2,该节点是非叶子节点,不存在右子树
那么lchild为前驱
3,如果该节点是叶子节点
那么后继是该叶子树根的数根的...(有树根就一直找下去)的左孩子
BiThrTree IPrePostNode(BiThrTree head,BiThrTree p)
{
BiTreePost post;
if(p->LTag==0)
{
post=p->lchild; //分析了具有左子树的中间节点情况
}
else{
post=p;
while(post->RTag==1&&post->rchild!=head)
{
post=post->rchild; //分析了不具有左子树的中间节点以及叶子节点的况
//在中序二叉树中任何一个叶子节点一定是以p->rchild节点为根的左子树的中序遍历的最后一个节点
}
post=post->rchild;
}
}
BiThrTree IPostPretNode(BiThrTree head,BiThrTree p)
{
BiTreePre pre;
if(p->RTag==0)
{
pre=p->rchild;
}
else{
pre=p;
while(pre->LTag==1&&pre->lchild!=head)
{
pre=pre->lchild;
}
pre=pre->lchild;
}
}
最后:1,线索二叉树在某种意义上就是可以反映二叉树某序的双向循环链表,在链表中存在特殊节点(head)来充当头结点。
2,线索二叉树本质上也是一种二叉树,仅有左右两个指针,因而,就算我们的确需要指针来进行先驱节点或是后继节点的寻找时我们不得不根据两种标签来区别该节点的指针究竟是结构指针还是次序指针。
3,一次得到遍历次序时,我们可以先把p指针指到次序指针的最开头的节点(也就是左下角节点)然后在存在次序指针的情况下直接找到后续节点不存在次序指针的情况下利用结构指针来找到下一个节点 如下BiThrTree InPost(BiThrTree T,BiThrTree p)函数 。