1. 线索二叉树的概念及结构
在有 n 个结点的二叉链表中共有 2n 个链域,但只有 n-1 个有用的非空链域,其余 n+1 个链域是空的。可以利用这空闲的 n+1 个空链域来存放遍历过程中结点的前驱和后继信息。
现规定:若结点有左子树,则其 LChild 域指向其左孩子,否则 LChild 域指向其前驱结点;若节点有右子树,则其 RChild 域指向其右孩子,否则 RChild 域指向其后继结点。
在这种存储结构中,指向前驱和后继结点的指针称为线索。以这种结构组成的二叉链表作为二叉树的存储结构,称为线索链表。对二叉树以某种次序进行遍历并且加上线索的过程称为线索化,线索化了的二叉树称为线索二叉树。
2. 二叉树的线索化(以中序线索树为例)
中序线索化采用中序递归遍历算法框架,设置一个指针 pre 始终记录刚访问过的结点。
① 如果当前遍历结点 bt 的左子域为空,则让左子域指向 pre ;
② 如果前驱 pre 的右子域为空,则让右子域指向当前遍历结点 bt ;
③ 为下次做准备,当前访问结点 bt 作为下一个访问结点的前驱 pre 。
/*建立中序线索树*/
BiTree pre;
void Inthread(BiTree bt) {
//对于bt所指的二叉树进行中序线索化,其中pre始终指向刚访问过的结点,其初值为NULL
if (bt != NULL) {
Inthread(bt->LChild); //线索化左子树
if (bt->LChild == NULL) {
//置前驱线索
bt->Ltag = 1;
bt->LChild = pre;
}
if (pre != NULL && pre->RChild == NULL) {
//置后继线索
pre->RChild = bt;
pre->Rtag = 1;
}
pre = bt; //当前访问结点为下一个访问结点的前驱
Inthread(bt->RChild); //线索化右子树
}
}
3. 线索二叉树的遍历(以中序线索树为例)
① 求出中序遍历次序下的第一个被访问结点;
② 连续求出刚遍历结点的后继结点,直至所有结点均被遍历。
/*遍历中序线索二叉树*/
void TInOrder(BiTree bt) {
BiTree p = bt;
while (p != NULL) {
while (p->Ltag == 0) {
//找中序遍历的第一个结点
p = p->LChild;
}
printf("%c ", p->data);
while (p->Rtag == 1 && p->RChild != NULL) {
p = p->RChild;
printf("%c ", p->data);
}
p = p->RChild;
}
}
4. 中序线索树完整实现代码
/*中序线索二叉树*/
# include<stdio.h>
# include<malloc.h>
/*二叉线索树的存储结构*/
typedef char DataType;
typedef struct Node {
DataType data;
int Ltag;
int Rtag;
struct Node* LChild;
struct Node* RChild;
}BiTNode, * BiTree;
/*按扩展先序遍历序列创建二叉链表*/
void CreateBiTree(BiTree* bt) {
//'.'表示空子树
char ch;
ch = getchar();
if (ch == '.')
*bt = NULL;
else {
*bt = (BiTree)malloc(sizeof(BiTNode));
(*bt)->data = ch;
(*bt)->Ltag = 0;
(*bt)->Rtag = 0;
CreateBiTree(&((*bt)->LChild));
CreateBiTree(&((*bt)->RChild));
}
}
/*建立中序线索树*/
BiTree pre;
void Inthread(BiTree bt) {
//对于bt所指的二叉树进行中序线索化,其中pre始终指向刚访问过的结点,其初值为NULL
if (bt != NULL) {
Inthread(bt->LChild); //线索化左子树
if (bt->LChild == NULL) {
//置前驱线索
bt->Ltag = 1;
bt->LChild = pre;
}
if (pre != NULL && pre->RChild == NULL) {
//置后继线索
pre->RChild = bt;
pre->Rtag = 1;
}
pre = bt; //当前访问结点为下一个访问结点的前驱
Inthread(bt->RChild); //线索化右子树
}
}
/*遍历中序线索二叉树*/
void TInOrder(BiTree bt) {
BiTree p = bt;
while (p != NULL) {
while (p->Ltag == 0) {
//找中序遍历的第一个结点
p = p->LChild;
}
printf("%c ", p->data);
while (p->Rtag == 1 && p->RChild != NULL) {
p = p->RChild;
printf("%c ", p->data);
}
p = p->RChild;
}
}
int main() {
BiTree bt;
printf("树的创建:");
CreateBiTree(&bt);
Inthread(bt);
printf("遍历结果:");
TInOrder(bt);
return 0;
}
5. 运行结果
参考:耿国华《数据结构——用C语言描述(第二版)》
更多数据结构内容关注我的《数据结构》专栏:https://blog.csdn.net/weixin_51450101/category_11514538.html?spm=1001.2014.3001.5482