线索二叉树
n个结点的二叉链表中含有n+1 (2n-(n-1)=n+1) 个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前趋和后继结点的指针(这种附加的指针称为"线索")。
线索化的实质就是将二叉链表中的空指针改为指向前驱或后继的线索。由于前驱和后继信息只有在遍历该二叉树时才能得到,所以,线索化的过程就是在遍历的过程中修改空指针的过程。
有了线索二叉树后,对它进行遍历时,其实就等于操作一个双向链表结构。
和双向链表结点一样,在二叉树链表上添加一个头结点,如下图所示,并令其lchild域的指针指向二叉树的根结点(图中第一步),其rchild域的指针指向中序遍历访问时的最后一个结点(图中第二步)。反之,令二叉树的中序序列中第一个结点中,lchild域指针和最后一个结点的rchild域指针均指向头结点(图中第三和第四步)。这样的好处是:我们既可以从第一个结点起顺后继进行遍历,也可以从最后一个结点起顺前驱进行遍历。
代码示例
#include<stdlib.h>
#include<stdio.h>
typedef char TElemType;
typedef enum {Link,Thread} PointerTag;
typedef struct BiThrNode
{
TElemType data;//结点数据
struct BiThrNode *lchild,*rchild;//左右孩子指针
PointerTag LTag;//左右标志
PointerTag RTag;
}BiThrNode, *BiThrTree;
BiThrTree pre=NULL;//全局变量,始终指向刚刚访问过的结点
//中序遍历线索化的递归函数,直接输出
void InThreading(BiThrTree p)
{
if(p)
{
InThreading(p->lchild);
printf("%c",p->data);
if(!p->lchild){
p->LTag=Thread;
p->lchild=pre;//最左下结点的左孩子指针指向前驱,这里是第3步
}
if(!p->rchild){
pre->RTag=Thread;
pre->rchild=p;
}
pre=p;
InThreading(p->rchild);
}
}
//建立头指针,使其左指针指向根结点,右指针指向遍历的最后一个结点
void InOrder_Thr(BiThrTree &head,BiThrTree T)
{
head=(BiThrTree)malloc(sizeof(BiThrNode));
head->LTag=Link;
head->RTag=Thread;
head->rchild=head;//先指向自己
if(!T)
head->lchild=head;
else
{
head->lchild=T;//第1步
pre=head;
InThreading(T);
//pre为最右下结点
pre->RTag=Thread;
pre->rchild=head;//第4步
head->rchild=pre;//第2步
}
}
//前序创建二叉树
void CreateBiTree(BiThrTree &T)
{
TElemType ch;
scanf("%c",&ch);
if(ch=='#') T=NULL;
else{
T=(BiThrTree)malloc(sizeof(BiThrNode));
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
int main()
{
BiThrTree T,head=NULL;
printf("请输入你想建立的二叉树(扩展前序序列)\n");
CreateBiTree(T);
printf("\n二叉树的中序序列为:\n");
InOrder_Thr(head,T);
}