通过考察各种二叉链表,不管儿叉树的形态如何,空链域的个数总是多过非空链域的个数。准确的说,n各结点的二叉链表共有2n个链域,非空链域为n-1个,但其中的空链域却有n+1个。如下图所示。
因此,提出了一种方法,利用原来的空链域存放指针,指向树中其他结点。这种指针称为线索。
记ptr指向二叉链表中的一个结点,以下是建立线索的规则:
(1)如果ptr->lchild为空,则存放指向中序遍历序列中该结点的前驱结点。这个结点称为ptr的中序前驱;
(2)如果ptr->rchild为空,则存放指向中序遍历序列中该结点的后继结点。这个结点称为ptr的中序后继;
显然,在决定lchild是指向左孩子还是前驱,rchild是指向右孩子还是后继,需要一个区分标志的。因此,我们在每个结点再增设两个标志域ltag和rtag,注意ltag和rtag只是区分0或1数字的布尔型变量,其占用内存空间要小于像lchild和rchild的指针变量。结点结构如下所示。
其中:
(1)ltag为0时指向该结点的左孩子,为1时指向该结点的前驱;
(2)rtag为0时指向该结点的右孩子,为1时指向该结点的后继;
(3)因此对于上图的二叉链表图可以修改为下图的养子。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
typedef struct Binode
{
char data;
struct Binode *lchild,*rchild;
int ltag,rtag;
} Binode,*Bitree;
Bitree pre;
void CreatTREE(Bitree &T)
{
char ch;
scanf("%c",&ch);
if(ch==' ')
{
T=NULL;
}
else
{
T=(Bitree)malloc(sizeof(Binode));
T->data=ch;
T->ltag=0;
T->rtag=0;
CreatTREE(T->lchild);
CreatTREE(T->rchild);
}
return;
}
void travel_threadtree(Bitree H) //中序遍历线索树 从头节点开始
{
Bitree p;
p=H->lchild; //p为二叉树头节点
while(p!=H)
{
while(p->ltag==0) //有左子树 则 一直往下
p=p->lchild;
printf("%c ",p->data);
while(p->rtag==1&&p->rchild!=H) //根据它的线索一直往后输出
{
p=p->rchild;
printf("%c ",p->data);
}
p=p->rchild; //当没有线索时 表示有右子树
}
return;
}
void thread(Bitree T) //线索化
{
if(T)
{
thread(T->lchild);
if(!T->lchild)
{
T->ltag=1;
T->lchild=pre;
}
if(!pre->rchild)
{
pre->rtag=1;
pre->rchild=T;
}
pre=T; //顺序是左子树 节点 右子树的中序遍历 所有 放这里
thread(T->rchild);
}
return;
}
void threading_(Bitree &H,Bitree T) //新增头节点
{
H=(Bitree)malloc(sizeof(Binode));
H->rchild=H;
H->rtag=0;
if(!T) //二叉树为空
{
H->lchild=H;
H->ltag=0;
}
else
{
pre=H;
H->lchild=T;
H->ltag=0;
thread(T);
H->rtag=1;
H->rchild=pre; //
pre->rchild=H; // 构成循环 以备跳出
}
return;
}
int main()
{
Bitree T,H;
CreatTREE(T);
threading_(H,T);
travel_threadtree(H);
return 0;
}