我们知道,一颗二叉树不总是有两颗子树,也就是存在左子树或右子树为空的情况,这样就造成了存储空间的浪费,利用这些空链域来存放结点的前驱和后继的信息,就可以保存在遍历过程中的前驱和后继信息了。
我们要将其线索化并用中序遍历的方法输出,按照中序遍历的顺序:先遍历左子树,再遍历根结点,最后遍历右子树,那么,其输出结果应该为:CBDAEF
线索二叉树的结构
用代码表示为
typedef enum{Link,Thread} Pointag;
//Link = 0表示指向左右孩子指针,Thread = 1表示指向前驱或后继的线索
typedef struct BiThNode
{
ElemType data;
struct BiThNode *lchild,*rchild;
Pointag ltag,rtag; //左右线索标志
}BiThNode,*BiThTree;
创建线索二叉树
//创建一颗线索二叉树
void CreateBiThTree(BiThTree *T)
{
char c;
scanf("%c",&c);
if(' ' == c)
{
*T = NULL;
}
else
{
*T = (BiThTree)malloc(sizeof(BiThNode));
(*T)->data = c;
(*T)->ltag = (*T)->rtag = Link; //默认存在左子树和右子树
CreateBiThTree(&(*T)->lchild);
CreateBiThTree(&(*T)->rchild);
}
}
中序遍历实现
//采用中序遍历
void InTraverse(BiThTree T)
{
if(T)
{
InTraverse(T->lchild);
if(!T->lchild)
{
T->ltag = Thread;
//如果没有左孩子,则让左子树指针指向前一个访问的结点
}
if(!Pre->rchild)
{
Pre->rtag = Thread;
Pre->rchild = T;
//前驱右孩子指针指向后继(当前结点T)
}
Pre = T; //记下当前结点
InTraverse(T->rchild);
}
}
Pre指针指向上一次访问的结点,在使用之前需初始化
void InOrderThreading(BiThTree *p,BiThTree T)
{
*p = (BiThTree)malloc(sizeof(BiThNode));
(*p)->ltag = Link;
(*p)->rtag = Thread;
(*p)->rchild = *p;
if(!T) //如果树为空
{
(*p)->lchild = *p;
}
else
{
(*p)->lchild = T; //p左子树指针指向根结点
Pre = *p; //初始时Pre指向根结点
InTraverse(T);
Pre->rchild = *p;
Pre->rtag = Thread;
(*p)->rchild = Pre;
}
}
//中序遍历,非递归
void InOrderTraversing(BiThTree T)
{
BiThTree p;
p = T->lchild; //p指向根接结点
while(p != T) //空树或遍历结束时 p == T
{
while(p->ltag == Link) //遍历左子树
{
p = p->lchild;
}
visit(p->data); //访问结点数据
while( p->rtag == Thread && p->rchild != T)
{
p = p->rchild;
visit(p->data);
}
p = p->rchild;
}
}
完整代码
#include <stdio.h>
#include<stdlib.h>
typedef enum{Link,Thread} Pointag;//Link = 0表示指向左右孩子指针,Thread = 1表示指向前驱或后继的线索
typedef char ElemType;
typedef struct BiThNode
{
ElemType data;
struct BiThNode *lchild,*rchild;
Pointag ltag,rtag;
}BiThNode,*BiThTree;
BiThTree Pre; //定义一个全局变量作为节点的前驱指针
//创建一颗线索二叉树
void CreateBiThTree(BiThTree *T)
{
char c;
scanf("%c",&c);
if(' ' == c)
{
*T = NULL;
}
else
{
*T = (BiThTree)malloc(sizeof(BiThNode));
(*T)->data = c;
(*T)->ltag = (*T)->rtag = Link; //默认存左子树和右子树
CreateBiThTree(&(*T)->lchild);
CreateBiThTree(&(*T)->rchild);
}
}
//访问数结点
void visit(char c)
{
printf("%c ",c);
}
//采用中序遍历
void InTraverse(BiThTree T)
{
if(T)
{
InTraverse(T->lchild);
if(!T->lchild)
{
T->ltag = Thread;
T->lchild = Pre; //如果没有左孩子,则让左子树指针指向前一个访问的结点
}
if(!Pre->rchild)
{
Pre->rtag = Thread;
Pre->rchild = T; //前驱右孩子指针指向后继(当前结点T)
}
Pre = T; //记下当前结点
InTraverse(T->rchild);
}
}
//设置Pre指针
void InOrderThreading(BiThTree *p,BiThTree T)
{
*p = (BiThTree)malloc(sizeof(BiThNode));
(*p)->ltag = Link;
(*p)->rtag = Thread;
(*p)->rchild = *p;
if(!T) //如果树为空
{
(*p)->lchild = *p;
}
else
{
(*p)->lchild = T;
Pre = *p;
InTraverse(T);
Pre->rchild = *p;
Pre->rtag = Thread;
(*p)->rchild = Pre;
}
}
//中序遍历,非递归
void InOrderTraversing(BiThTree T)
{
BiThTree p;
p = T->lchild; //p指向根接结点
while(p != T) //空树或遍历结束时 p == T
{
while(p->ltag == Link) //遍历左子树
{
p = p->lchild;
}
visit(p->data); //访问结点数据
while( p->rtag == Thread && p->rchild != T)
{
p = p->rchild;
visit(p->data);
}
p = p->rchild;
}
}
int main()
{
BiThTree P,T = NULL;
CreateBiThTree(&T);
InOrderThreading(&P,T);
printf("中序输出结果为:");
InOrderTraversing(P);
printf("\n");
return 0;
}
输入:ABC_ _ D _ _ E _ F _ _ ( _ 代表空格 )
输出结果为: