数据结构---线索二叉树

线索二叉树

基于直接获得到结点在任意序列的前驱和后继的需求,引入线索二叉树

为了不降低存储密度,将二叉链表的空链域来存放结点的前驱和后继信息

增加两个标志域

image-20220127165715649

当Tag为零则child指向孩子,为1则指向前驱(L)或后继(R)

线索链表的存储表示

typedef struct BiThrNode 
{
TElemType data; //数据域
struct BiThrNode *lchild,*rchild;//左右孩子指针
int LTag, RTag;//左右标志
} BiThrNode,*BiThrTree;

这样遍历二叉树使其变为线索二叉树实现了对其的线索化

image-20220127170751227

为了不让无左右孩子又无前驱或后继的的结点指针域置空,这里就添加了头结点,其 lchild域的指针指向二叉树的根结点,其 rchild 域的指针指向中序遍历时访问的最后一个结点。

同时,令二叉树中序序列中第一个结点的 lchild 域指针和最后一个结点 rchild 域的指针均指向头结点

image-20220127172252294

以结点p为根的子树中序线索化
void InThreading(BiThrTree p)
{
if(p) //根结点不为空,开始左子树线索化
 {
InThreading (p-> lchild) ; //左子树递归线索化
if (! p-> lchild) //判断左孩子是否为空
  {
p->LTag=l; //为空将LTag赋值为1
p-> lchild=pre; //左孩子指向前趋
  }
else p->LTag=O; //不为空LTag赋值为0
if { ! pre-> rchild) //判断pre右孩子是否为空
  {
pre-> RTag=l; //为空则为RTag赋值为1
pre-> rchild=p; //pre的右孩子指向后继
  }
else p->RTag=O; //不为空RTag赋值为0
pre=p; //让pre指针指向p,即将退出循环,此时的p相当于指向下一个p的前趋
InThrending (p-> rchild) ;//右子树递归线索化
 }
}
带头结点的二叉树中序线索化
void InOrderThreading(BiThrTree &Thrt,BiThrTree T)
{
Thrt=new BiThrNode; //new一个头结点
Thrt->LTag=O; // 头结点有左孩子, 若树非空,则其左孩子为根结点
Thrt-> RTag=l; // 头结点的右孩子指针指向中序遍历访问的最后一个结点
Thrt-> rchild=Thrt; //初始化时,右孩子指针指向自身
if (!T) Thrt-> lchild=Thrt; //如果T为空,则左孩子指针也指向自身
else //二叉树不为空
{
Thrt-> lchild=T;//头结点的左孩子指针指向根结点
pre=Thrt; //开始时后继指针指向头结点
InThreading(T); //继续进行二叉树的中序线索化
pre-> rchild=Thrt; //访问的最后一个结点的右孩子指针指向头结点
pre-> RTag=l; //没有右孩子,将右线索置1,它的后继是头结点
Thrt-> rchild=pre;//最后一个结点访问后它就是pre,将头结点的右孩子指针指向最后一个结点
}
}
遍历中序线索二叉树
void InOrderTraverse_Thr(BiThrTree T)
{//T指向头结点,其左孩子指针指向根结点
p=T->lchild; //将p指向根结点
while(p!=T)//头结点为空即为空树,p==T
{
while (p-> LTag==O) p=p->lchild;//当左边的标识域为0,即指向左孩子,p指针就移动到左孩子上
cout<<p->data;//否则即左边的标识域是1,指向前驱,没有左子树,输出此时的p的数据域(结点的值)
while (p-> RTag==l&&p-> rchild ! =T) //右标识域为1,即没有右子树&&右孩子指针指向头结点
{
p=p-> rchild; //p指针移动到右孩子上
cout<<p->data;//输出右孩子的数据域
}
p=p-> rchild;//转向p的右子树
}
}

时间复杂度为O(n)实际上每个结点都经过了三次,但是常数系数不影响时间复杂度的计算

空间复杂度为O(0),不需要另外空间实现递归操作

posted on 2022-02-06 20:31  眉目作山河  阅读(158)  评论(0编辑  收藏  举报

导航