线索化二叉树的实质就是把二叉树原来的空指针改为指向前驱和后继结点,由此,二叉树的线索化存储结构定义如下:
typedef enum{Link,Thread} PointerTag; //枚举类型,Link=0表示指向左右孩子指针,Thread=1表示指向前驱结点或后继结点
typedef struct BiThrNode
{
ElemType data; //数据域
struct BiThrNode* lchild; //左孩子结点指针
struct BiThrNode* rchild; //右孩子结点指针
PointerTag LTag; //左标志
PointerTag RTag; //右标志
}BiThrNode, *BiThrTree;
1. 利用中序遍历进行中序线索化的递归函数代码:
BiThrTree pre; //全局变量,用来记录已经访问过的结点
void InThread(BithrTree p)
{
if(p) //如果当前根结点不为空,进行如下操作。若为空,结束
{
InThread(p->lchild); //递归调用。找到以当前根结点为根的最左边的结点
if(!p->lchild) //如果左孩子为空,那么让左标志为1,以表示前驱,左孩子结点指针指向前一个被访问过的结点
{
p->LTag=Thread;
p->lchild=pre;
}
if(!pre->rchild) //如果前驱结点的右孩子为空,那么此时前驱结点的右孩子结点应该指向当前正在访问的结点
{
pre->RTag=Thread;
pre->rchild=p;
}
pre=p; //刚刚被访问的节点要变成当前正在访问的,但已经操作完成的结点
InThread(p->rchild); //递归右子树进行线索化
}
}
2. 中序遍历线索化二叉树
思想:在传入的线索二叉树中,我们可以添加一个头结点,该头结点在最上面的根层,头结点的左孩子指向原根节点,没有右孩子,所以右标志为1,右孩子指针指向其后继结点为原树最右边的结点,原树最右边结点的后继结点为该头结点,原树的最左边的结点的前驱结点为该头结点。之后就可以把这棵线索二叉树当成一个循环链表来进行操作了。中序遍历代码如下:
void InOrderThrTree(BiThrTree H)
{
BiThrTree p=H->lchild; //初始化一个结点指针来遍历线索二叉树
while(p!=H) //循环结束条件为空树或者遍历完
{
while(p->LTag==Link) //当结点左标志为0,表明该根节点有左孩子,则继续寻找最左边的结点
{
p=p->lchild;
}
printf("%c ",p->data); //循环条件结束,表明该结点没有左孩子,则说明找到了最左边的结点,打印数据域即可
while(p->RTag==Thread && p->rchild!=H) //当当前结点的右标志为1,并且不是最后一个结点时,打印当前结点的后继结点数据域
{
p=p->rchild; //当前结点后移为自己的后继结点
printf("%c ",p->data); //打印数据域
}
p=p->rchild; //循环结束时,要么当前结点存在右孩子或者是最后一个结点时,当前结点变为其右孩子结点,再将其看做一棵树,进行遍历
}
}