由于二叉树的叶子结点或者只有一个孩子的父节点的孩子节点处是没有存放指针的,而且在每次遍历时仍然要遍历这些空地址,浪费程序运行时间;为了解决这些问题,利用这些空地址存放指向结点在某种遍历次序下的前驱和后继节点的地址。这样建成的树即为线索二叉树。
为了让计算机运行的时候能够准确分辩出孩子节点处存放的是孩子节点的地址还是前驱或者后继节点的地址,还需在每个节点增加两个标志域Ltag和Rtag;故新的节点结构为:
其中 :
• Ltag 为 0 时指向该结点的左孩子,为 1 时指向该结点的前驱。
• Rtag 为 0 时指向该结点的右孩子,为 1 时指向该结点的后继 .
故线索二叉树的结构体定义为:
typedef char theatype;
typedef enum{LINK=0,THREAD =1}PointTag;//枚举类型
typedef struct BiThrNode
{
BiThrNode *leftchild;
BiThrNode *rightchild;
PointTag Ltag;
PointTag Rtag;
theatype data;
}BiThrNode , *ThreadBinaryTree;
首先创建一个基本的二叉树:
BtNode * CreateTree1()
{
BtNode *s = NULL;
ElemType item;
scanf_s("%c",&item);
if(item != '#')
{
s = Buynode();
s->data = item;
s->leftchild = CreateTree1();
s->rightchild = CreateTree1();
}
return s;
}
这里只是简单的写一个作为参考,其他创建方法见之前的博客;
**创建中序线索化二叉树:**
中序线索化二叉树就是以中序遍历结果为标准改变左右节点的指向,并以此确定其前驱和后继;
void Make(BiThrNode *ptr ,BiThrNode *&pre)
{
if(ptr != NULL)
{
Make(ptr->leftchild,pre); //遍历左子树
if (ptr->leftchild ==NULL) // 如果该节点的左孩子为空
{
ptr->leftchild =pre; //左孩子为空(或者在中序遍历中它的前驱)
ptr->Ltag =THREAD; //左标志位变成1
}
if (pre != NULL&&pre->rightchild == NULL) //右孩子为空
{
pre->rightchild =ptr; //右孩子孩子为中序遍历中它的后继
pre->Rtag = THREAD;//右标志位变为1
}
pre=ptr; //更新访问过的节点位置
Make(ptr->rightchild,pre);
}
}
void MakeThreadTree(BiThrNode *ptr) //中序遍历线索二叉树
{
BiThrNode *pre=NULL; //记录访问过的节点
Make(ptr,pre);
pre->rightchild = NULL; //最右叶子结点没有后继或者右孩子,它的右孩子节点处仍然指向空
}
**非递归中序遍历线索化二叉树**
利用循环等遍历二叉树:
BiThrNode * first(BiThrNode *ptr)
{
while (ptr != NULL &&ptr->Ltag != THREAD)//当ptr为空或者左标志域为1时找到最左节点
{
ptr=ptr->leftchild;
}
return ptr;
}
BiThrNode * next(BiThrNode *p)
{
if(p == NULL)return NULL;
if (p->Rtag == THREAD) //当p的左标志域为1时,没有左孩子并将指针转到该节点的后继,即下一个需要打印的字符
{
return p->rightchild;
}
else
{
return first(p->rightchild);//还有右孩子则遍历右孩子
}
}
void ThrInOrder(BiThrNode * ptr) //非递归中序遍历线索二叉树
{
for (BiThrNode *p = first(ptr);p != NULL;p =next(p))
{
printf("%c ",p->data);
}
}
for (BiThrNode *p = first(ptr);p != NULL;p =next(p))
这一句代码是用first函数将p指向最左孩子节点处,打印,再将p指向右边,当p指向null时,结束循环。
**逆序非递归中序遍历线索化二叉树**
即打印顺序为:右子树,根节点,左子树;
BiThrNode *right(BiThrNode *ptr)
{
while(ptr != NULL && ptr->Rtag != THREAD)
{
ptr = ptr ->rightchild;
}
return ptr;
}
BiThrNode *left(BiThrNode *p)
{
if (p == NULL)
{
return NULL;
}
if (p->Ltag== THREAD)
{
return p->leftchild;
}
else
{
return right(p->leftchild);
}
}
void resThrInOder(BiThrNode *ptr) //逆序非递归中序遍历中序线索化二叉树
{
for (BiThrNode * p = right(ptr);p != NULL;p = left(p))
{
printf("%c ",p->data);//现将指针指向最右孩子,然后转到左边
}
}