线索二叉树的基本概念
对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域,利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树。
这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)
在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化。
来自百度百科,由“科普中国”科学百科词条编写与应用工作项目 审核 。
线索二叉树的基本操作
二叉树的结构定义
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef char TElemType;
// Link(值为 0 )表示指向左右孩子指针,Thread(值为 1 )表示指向前驱或后继的指针
typedef enum {Link,Thread} PointerTag;
typedef struct BiThrNode {
TElemType data;
struct BiThrNode* lchild, * rchild; //左右孩子指针
PointerTag LTag, RTag; //左右标志
}BiThrNode;
typedef struct BiThrNode* BiThrTree;
前序构造二叉链表
/* 前序构造二叉链表 */
int CreateBiThrTree(BiThrTree* T)
{
TElemType e;
scanf(" %c", &e);
if (e == '#')
*T = NULL;
else
{
*T = (BiThrTree)malloc(sizeof(BiThrNode));
if (!(*T)) //如果分配失败
exit(-1);
(*T)->data = e;
CreateBiThrTree(&(*T)->lchild);
if ((*T)->lchild) //有左孩子
(*T)->LTag = Link;
CreateBiThrTree(&(*T)->rchild);
if ((*T)->rchild) //有右孩子
(*T)->RTag = Link;
}
return OK;
}
中序遍历线索化
需定义一个 BiThrTree 类型的全局变量 pre,(用于)始终指向刚刚访问的结点
/* 中序遍历线索化 */
BiThrTree pre; //全局变量,(用于)始终指向刚刚访问的结点
void InThreading(BiThrTree p)
{
if (p)
{
InThreading(p->lchild);
if (!p->lchild) //如果没有左孩子
{
p->LTag = Thread; //前驱线索
p->lchild = pre; //左孩子指向前驱
}
if (!pre->rchild) //如果前驱没有右孩子
{
pre->RTag = Thread; //后继线索
pre->rchild = p; //前驱右孩子指针指向后继(当前结点p)
}
pre = p; //保持 pre 始终指向 p 的前驱
InThreading(p->rchild);
}
}
中序遍历线索化,Thrt指向头结点
/* 中序遍历线索化,Thrt指向头结点 */
void InOrderThreadig(BiThrTree* Thrt, BiThrTree T)
{
*Thrt = (BiThrTree)malloc(sizeof(BiThrNode));
if (!(*Thrt)) //如果分配失败
exit(-1);
(*Thrt)->LTag = Link; //建立头结点
(*Thrt)->RTag = Thread;
(*Thrt)->rchild = (*Thrt); //右指针回指
if (!T) //如果二叉树为空,左指针回指
(*Thrt)->lchild = *Thrt;
else
{
(*Thrt)->lchild = T;
pre = (*Thrt); //可以让下面中序遍历线索化时,中序序列的
//最左边的结点的lchild指向头结点
InThreading(T); //中序遍历线索化
pre->rchild = *Thrt; //最后一个结点指向一个头结点
pre->RTag = Thread; //最后一个结点线索
(*Thrt)->rchild = pre;
}
}
(非递归法)中序遍历二叉线索树T(带头结点)
/* (非递归法)中序遍历二叉线索树T(头结点) */
void InOrderTraverse_Thr(BiThrTree T)
{
BiThrTree p;
p = T->lchild; //p指向根结点
while (p != T) //空树或遍历结束
{
while (p->LTag == Link)
p = p->lchild;
printf("%c\n", p->data);
while (p->RTag == Thread && p->rchild != T)
{
p = p->rchild; //访问后继结点
printf("%c\n", p->data);
}
p = p->rchild; //进入右子树
}
}