数据结构:线索二叉树

本文深入探讨了线索二叉树的概念,介绍了如何构建中序线索二叉树,并提供了遍历中序线索二叉树的方法。文章详细解释了线索二叉树的节点结构,以及如何在遍历过程中存储节点的前驱和后继信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、线索二叉树的概念

以二叉链表为存储结构时,只能找到结点的lchild和rchild,要想得到结点的“前驱和后继”,则必须遍历整个二叉链表。为了更方便的得到节点的“前驱和后继”,学者引入了 线索二叉树的概念,所谓线索二叉树,是指在遍历二叉树的时候,将节点的“前驱和后继”信息存储在其为空的 lchild和rchild 中。
线索二叉树的结点 结构如下:

lchildLTagdatarchildRTag
LTag=1,lchild存放的是前驱信息;
LTag=0,lchild存放的是左孩子;
RTag=1,rchild存放的是后继信息;
RTag=0,rchild存放的是右孩子信息;

二、中序线索二叉树的构建

1、线索二叉树节点的存储结构
typedef struct BiThrNode{
TElemType data;
struct BiThrNode *lchild,*rchild;
int LTag,RTag;
}BiThrNode,*BiThrTree;
2、构建中序线索二叉树
//以p为根的子树中序线索化
void InThreading(BiThrTree p){
if(p){ //如果结点p不为空
InThreading(p->lchild); //对结点p的左孩子进行中序线索化
if(!p->lchild){ //如果P的lchild为Nulll,将其存放p的前驱信息
p->LTag = 1; //将左孩子存放p的前驱信息
p->lchild = pre;  
}
else{p->LTag=0;} //如果P的左孩子不为空,则将LTag=0
if(!pre->rchild){ //如果 前驱Pre的右孩子为NULL,存放pre的后继信息,即:p
pre->RTag = 1;
pre->rchild = p;
}
else{p->RTag = 0;} //由于pre只会 管pre->rchild=NULL的情况,所以要在这里提前为p->RTag=0,如果下一轮pre->rchild != NULL,则即便不赋值pre->RTag也没关系
pre = p; //将p作为pre,线索化其右孩子
InThreading(p->rchild); 
}

//带头结点的二叉树中序线索化
//头结点的lchild指向二叉树根节点;rchild指向中序遍历二叉树的最后一个结点;
void InOrderThreading(BiThrTree &Thrt,BiThrTree T){
Thrt = new BiThrNode; //创建头结点
Thrt->LTag = 0;
Thrt->RTag = 1;
Thrt->rchild = Thrt; //先让头结点的右孩子指向自己
if(!T){Thrt->lchild=Thrt;}
else{
Thrt->lchild = T; //头结点的左孩子指向线索二叉树的根节点;右孩子最终指向中序遍历的最后一个结点
pre = Thrt; //设Thrt为 中序遍历前 的前驱
InThreading(T); //中序线索化二叉树
pre->RTag = 1; //此时的pre为中序遍历的最后一个结点
pre->rchild = Thrt; //令pre指向头结点
Thrt->rchild = pre; //令头结点的右孩子指向 中序遍历最后一个结点
}
}
3、遍历中序线索二叉树
void InOrderTraverse_Thr(BiThrTree T){
//T为头结点:lchild为二叉树根;rchild为中序遍历最后一个元素
p=T->lchild;
while(p != T){ //中序遍历二叉树最后一个节点的rchild后继为头结点T
while(p->LTag == 0){p=p->lchild;} //如果p左结点为左孩子,则一直遍历,直到其左结点记录的是前驱信息,则说明,此结点为第一个中序遍历的结点,其前驱为 头结点
cout<<p->data; //输出第一个结点信息
while(p->RTag == 1 && p->rchild != T){p=p->rchild;cout<<p->data;} //如果结点右结点记录的是后继信息,则输出该后继信息,并接着遍历该结点的后继信息,即:rchild,直到节点的右结点为右孩子,停止循环
p=p->rchild; //以中序遍历右孩子子树
}
}

Note that:
中序遍历线索二叉树,结点p前驱后继很好找:
1、当p->LTag = 1,则p->lchild为p的前驱;
2、当p->LTag = 0,则p有左子树,其左子树中最右下的结点即为p的前驱;
3、当p->RTag = 1,则p->rchild为p的后继;
4、当p->RTag = 0,则p有右子树,其右子树中最左下的结点即为p的后继;

与中序遍历相比, 先序遍历和后序遍历 线索二叉树,结点p的前驱 和 后继 查找起来有点麻烦。
1、先序遍历线索二叉树

  1. 如果p->LTag = 1,则p结点的前驱为p->lchild;
  2. 如果p->LTag = 0,则p结点的前驱要分情况讨论:
    当p为根节点时,p的先驱为 空;
    当p为左结点时,p的先驱为 其双亲结点;
    当p为右结点时,p的先驱为 其兄弟左子树的最右下的结点(若存在) 或 其双亲结点;
  3. 如果p->RTag = 1,则p的后继为p->rchild;
  4. 如果p->RTag = 0,则p的后继为其左孩子p->lchild(若存在) 或 右子树根;

2、后序遍历线索二叉树

  1. 如果p->LTag = 1,则p的前驱为p->lchild;
  2. 如果p->LTag = 0,则p的前驱为:其右孩子p->rchild(若存在) 或 其左孩子;
  3. 如果p->RTag = 1,则p的后继为p->rchild;
  4. 如果p->RTag = 0,则p的后继分情况讨论:
    当p为根节点时,其后继为 空;
    当p为左结点时,其后继为兄弟右子树最左下的结点(若存在) 或 其双亲结点;
    当p为右结点时,其后继为其双亲结点;

参考资料:《数据结构》 严蔚敏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sarah ฅʕ•̫͡•ʔฅ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值