对于一般的二叉树,若它有n个链表,必有n+1个空链域(也就是为NULL的指针,即空指针)。
线索二叉树充分利用了这空指针,使得节点可以在没有左孩子或右孩子时,使得左孩子指针指向节点前驱,右孩子指针指向节点后继。对于同一个节点,它的前驱和后继与遍历方式有关,举例说明:中序遍历时根节点的前驱是遍历左子树时最后访问到的节点,而在后序遍历时前驱可能是左孩子也可能是右孩子,二者显然是不同的,同一个节点的后继也类似,因遍历方式不同而不同。
以下是线索二叉树中序遍历的代码实现。
#include <stdio.h>
#define ElemType int
typedef struct BiTNode
{
ElemType data;
BiTNode *lchild, *rchild;
int LTag, RTag;
} BiTNode, *BiTree;
void InsertElem(BiTree &T, ElemType e) //插入函数:对每一个结点找到其合适位置并插入
{
if (!T) //找到空节点
{
T = new BiTNode;
T->data = e;
T->lchild = T->rchild = NULL;
}
else
{
if (T->data > e)
InsertElem(T->lchild, e); //根据当前节点值与待插入值之间的大小关系,分别向左向右寻找
else
InsertElem(T->rchild, e);
}
}
void Create(BiTree &T, int ElemNum) //构建二叉排序树
{
for (int i = 0; i < ElemNum; i++)
{
ElemType Element;
scanf("%d", &Element);
InsertElem(T, Element); //插入每一个输入的值
}
}
void InOrderTraverse1(BiTree T) //中序遍历的递归算法
{
if (T)
{
InOrderTraverse1(T->lchild);
printf("%d ", T->data);
InOrderTraverse1(T->rchild);
}
}
BiTree pre;
void InThreading(BiTree T) //对以T为根节点的子树进行中序线索化
{
if (T)
{
InThreading(T->lchild); //对左子树线索化
if (!T->lchild) //T的左子树为空,左孩子指针指向前驱
{
T->LTag = 1;
T->lchild = pre;
}
else
T->LTag = 0;
if (!pre->rchild) //pre的右子树为空,T成为pre的后继
{
pre->RTag = 1;
pre->rchild = T;
}
else
pre->RTag = 0;
pre = T; //保持pre为T的前驱
InThreading(T->rchild); //对右子树线索化
}
}
void InOrderThreading(BiTree &Thrt, BiTree T) //Thrt指向头结点
{
Thrt = new BiTNode; //初始化一个头结点
Thrt->LTag = 0; //树非空时头结点的左孩子指针指向树的根节点
Thrt->RTag = 1; //头结点的右孩子指针线索化,指向自己
Thrt->rchild = Thrt;
if (!T)
{
Thrt->LTag = 1;
Thrt->lchild = Thrt; //空树头结点的左指针指向自己
}
else
{
Thrt->lchild = T;
pre = Thrt; //头结点所有值已完成初始化,将Thrt赋值给pre,作为一开始的前驱
InThreading(T);
pre->RTag = 1;
pre->rchild = Thrt; //中序线索化函数调用完时,pre为最右节点
Thrt->rchild = pre;
}
}
void InOrderTraverse2(BiTree T) //中序遍历线索化的二叉树,传入参数为头结点
{
BiTree p = T->lchild; //T为线索二叉树的头节点,p指向根节点
while (p != T)
{
while (!p->LTag)
p = p->lchild;
printf("%d ", p->data); //输出左子树为空的第一个节点:最“左下”的节点,这应当是中序遍历最先输出的点
while (p->RTag && p->rchild != T) //依次访问后继节点并输出,直到最后一个节点
{
p = p->rchild;
printf("%d ", p->data);
}
p = p->rchild; //回到头结点,结束循环
}
}
int main()
{
int ElemNum;
scanf("%d", &ElemNum);
BiTree T = NULL;
Create(T, ElemNum);
printf("递归形式的先序遍历:");
InOrderTraverse1(T); //递归形式的中序遍历
printf("\n--------------------------------------------------\n");
BiTree Thrt;
InOrderThreading(Thrt, T); //线索化二叉树
printf("线索化后的先序遍历:");
InOrderTraverse2(Thrt); //线索化后的中序遍历
return 0;
}