#include <stdio.h>
#include <stdlib.h>
typedef enum{Link,Thread} PointerTag;
typedef struct ThrBiTreeNode{ //树的节点
char data;
struct ThrBiTreeNode *lchild,*rchild;
PointerTag ltag,rtag; <span style="font-family: Arial, Helvetica, sans-serif;">//枚举类型变量,用于线索二叉树中,指示左右孩纸指针lchild,rchild的意义:指向其孩纸or后继</span>
} ThrBiTreeNode,*ThrBiTree;
ThrBiTree pre,p; //全局变量,pre为树的头,若树不为空,pre->lchild指向树的跟节点,pre->rchild指向中序遍历的起始节点
void CreateThrBiTree(ThrBiTree *T) //先序(根节点-左子树-右子树)创建线索二叉树
{
if(!T) return;
char c;
scanf("%c",&c);
if(c==' ')
(*T)=NULL; //没有孩纸的节点的lchild或rchild为NULL
else
{
(*T)=(ThrBiTree)malloc(sizeof(ThrBiTree));
if(!(*T)) return;
(*T)->data=c;
(*T)->ltag=Link;
(*T)->rtag=Link; //创建线索二叉树时,所有节点的lchild,rchild都指向其孩纸,没有孩纸的为NULL
CreateThrBiTree(&(*T)->lchild);
CreateThrBiTree(&(*T)->rchild);
}
}
void InOrderTraversing(ThrBiTree T)
{
if(!T) return;
InOrderTraversing(T->lchild);
if(!T->lchild)
{
T->ltag=Thread;
T->lchild=p;
}
if(!p->rchild)
{
p->rtag=Thread;
p->rchild=T;
}
p=T;
InOrderTraversing(T->rchild);
}
void InOrderTraverse(ThrBiTree T) //中序遍历线索二叉树,利用值为NULL的lchild及rchild空间确定(存放)其前驱后继
{
pre=(ThrBiTree)malloc(sizeof(ThrBiTreeNode)); //pre为ThrBiTree类型指针,不存放数据,是树的头
if(!pre) return;
pre->ltag=Link;
pre->rtag=Link;
pre->lchild=pre;
pre->rchild=pre; //若树T为空,树头的lchild与rchild都指向梳头自身,可利用if(pre->lchild==pre && pre->rchild==pre)判断树是否为空树
if(T)
{
pre->lchild=T; //树T不为空,树头的左孩纸指向树根
pre->rchild=NULL; //树头的有孩纸是要指向中序遍历的起始节点的,中序遍历前在此处初始化为NULL,用于中序遍历时InOrderTraversing()中第8行的判断
p=pre; //p用于记录某个节点的前驱节点
InOrderTraversing(T);
if(!p->rchild) //中序遍历的尾节点指向树的头pre
{
p->rchild=pre;
p->rtag=Thread;
}
}
else
return;
}
void Print(ThrBiTree pre) //输出对树中序遍历后的结果
{
if(!pre) return;
ThrBiTreeNode* pt=pre->rchild;
ThrBiTreeNode* t=(ThrBiTreeNode*)malloc(sizeof(ThrBiTreeNode));
while(pt!=pre)
{
printf("%c",pt->data);
if(pt->rtag==Thread) //此处必须作此判断,原因见程序后图2解析
pt=pt->rchild;
else
{
t=pt->rchild;
while(t->ltag==Link)
{
t=t->lchild;
}
if(t->ltag==Thread && t->lchild==pt)
pt=t;
}
}
}
void main()
{
ThrBiTree *T=(ThrBiTree*)malloc(sizeof(ThrBiTree));
CreateThrBiTree(T);
InOrderTraverse(*T);
Print(pre);
free(pre);
free(T);
}
程序建立的二叉树模型:
前序创建二叉树时的输入为: ( _ 表示输入为空格)
ABD_H_ _E_ _CF_I_ _GJ_ _ _
中序遍历二叉树顺序为:
DHBEAFICJG
线索二叉树中序遍历的前驱后继表示为:
pre->ltag==Link,pre->lchild指向根节点A,pre->rtag==Thread,pre->rchild指向中序遍历的起始节点D
如图所示,并不是每一个节点都能通过lchild得到自身的前驱节点,不是每一个结点都能通过rchild得到自身的后继结点。例如:
节点D的后继结点是H,但是D->rtag==Link,所以不能以为D的后继节点就是D->rchild,虽然在本例本树中D的后继结点就是其右孩纸,但直接取后继节点为D->rchild是错误的。所以在Print()函数中需要判断。