线索二叉树:
对于一个有n个结点的二叉链表,每个结点有指向左右孩子的两个指针域,所以一共是2n个指针域。而n个结点的二叉树一共有n-1条分支线,也就是说存在n+1个空指针域。
我们可以考虑利用那些空地址,存放指向结点在某种遍历次序下的前驱和后继结点的地址。
我们把这种指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树。
我们对二叉树以某种次序遍历使其变为线索二叉树的过程称作是线索化。线索化的过程就是在遍历的过程修改空指针的过程。
其实线索二叉树,等于把一棵二叉树转变成了一个双向链表。
线索二叉树结构实现:
typedef enum {Link, Thread} PointerTag;
typedef struct BiThrNode
{
TElemType data;
struct BiThrNode *lchild, *rchild;
PointerTag LTag;
PointerTag RTag;
} BiThrNode, *BiThrTree;
BiThrTree pre;
void InThreading(BiThrTree p)
{
if (p)
{
InThreading(p->lchild);
if (!p->lchild)
{
p->LTag = Thread;
p->lchild = pre;
}
if (!pre->rchild)
{
pre->RTag = Thread;
pre->rchild = p;
}
pre = p;
InThreading(p->rchild);
}
}
遍历线索二叉树:
在二叉树线索链表上添加一个头结点,并令其lchild域的指针指向二叉树的根结点,其rchild域的指针指向中序遍历访问的最后一个结点。反之,令二叉树的中序序列中的第一个结点中,lchild域指针和最后一个阶段的rchild域指针均指向头结点。这样定义的好处就是我们既可以从第一个结点其顺后继进行遍历,也可以从最后一个结点起顺前驱进行遍历。
Status InOrderTraverse_Thr(BiThrTree T)
{
BiThrTree p;
p = T->lchild;
while (p != T)
{
while (p->LTag == Link)
p = p->lchild;
printf("%c", p->data);
while (p->RTag == Thread && p->rchild != T)
{
p = p->rchild;
printf("%c", p->data);
}
p = p->rchild;
}
return OK;
}
它等于是一个链表的扫描,所以时间复杂度为 O(n)。