在使用二叉树链式存储过程中 我们用‘#’占位不存在的结点 如下图所示
- 我们可以观察下如果每个空结点都占位符‘#’来代替 那么 占位符为n+1(n为二叉树实际结点) 那么会造成空间浪费 那么我们是否可以利用这些空结点去存储一些我们链的一些信息呢 实际是可以的 这种利用空结点存储链相关信息的方式就叫线索化二叉树
线索化二叉树的构建规则
- 结点左子树为空 利用左孩子指向它的前驱结点
- 结点的右子树为空 利用右孩子指向它的后继结点
- !!!注意:线索化二叉树要统一遵寻某种遍历方式
定义线索化二叉树的结构体
代码实现
#include <stdio.h>
#include "stdlib.h"
#include "math.h"
#include "time.h"
#include "string.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */
/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Status;
typedef char CElemType;
/* 字符型以空格符为空 */
CElemType Nil='#';
#pragma mark--二叉树构造**
int indexs = 1;
typedef char String[24]; /* 0号单元存放串的长度 */
String str;
Status StrAssign(String T,**char** *chars){
T[0] = strlen(chars);
int i;
for (i = 1; i <= T[0]; i++) {
T[i] = *(chars+i-1);
}
return OK;
}
//枚举 区别是左右孩子还是线索化
/**
Link ==0 表示左右孩子
Thread== 1 表示线索化
*/
typedef enum {Link,Thread}PointerTag;
/**
线索化 二叉树的结构体
*/
typedef struct BithrNode{
CElemType data;
struct BithrNode* lchild,* rchild;
PointerTag LTag;
PointerTag RTag;
}BithrNode,*BiThrTree;
//创建一个二叉树
Status CreateBiThrTree(BiThrTree *T){
CElemType ch = str[indexs++];
if (ch == Nil) {
*T = NULL;
} else {
*T = (BiThrTree)malloc(**sizeof**(BithrNode));
(*T)->data = ch;
CreateBiThrTree(&(*T)->lchild);
if ((*T)->lchild) {
(*T)->LTag = Link;
}
CreateBiThrTree(&(*T)->rchild);
if ((*T)->rchild) {
(*T)->RTag = Link;
}
}
return OK;
}
//线索化二叉树
BithrNode * pre; //记录下上个节点
/* 中序遍历进行中序线索化*/
void InThreading(BiThrTree p){
if (!p) **return**;
//左子化
InThreading(p->lchild);
if (p->lchild == **NULL**) {
p->lchild = pre;
p->LTag = Thread;
} else {
p->LTag = Link;
}
if (pre->rchild == **NULL**) {
pre->RTag = Thread;
pre->rchild = p;
} else {
pre->RTag = Link;
}
pre = p;
InThreading(p->rchild);
}
/* 中序遍历二叉树T,并将其中序线索化,Thrt指向头结点 */
Status InOrderThreading(BiThrTree *Thrt , BiThrTree T){
*Thrt = (BiThrTree)malloc(sizeof(BithrNode));
(*Thrt)->LTag = Link;
(*Thrt)->RTag = Thread;
(*Thrt)->rchild = *Thrt;
if (!T) {
(*Thrt)->lchild = *Thrt;
} else {
pre = *Thrt;
(*Thrt)->lchild = T;
InThreading(T);
pre->rchild = *Thrt;
pre->RTag = Thread;
(*Thrt)->rchild = pre;
}
return OK;
}
- 在构建线索化二叉树的时候添加了一个头结点 如下图所示
-
T作为头结点 左子树(作为子树)指向 A 右子树(作为线索化)指向最后一个结点
-
第一个节点 前驱指向T 做后一个结点后继指向T
-
那么我们在遍历二叉树的时候可以利用之前构造的线索化信息 不需要递归也能从头到后找到任意一个结点
/*中序遍历二叉线索树T*/
Status InOrderTraverse_Thr(BiThrTree T){
BiThrTree p;
p = T->lchild;
while (p!=T) {
while (p->LTag == Link) {
p = p->lchild;
}
printf("%c ",p->data);
while (p->RTag == Thread && p->rchild != T) {
p = p->rchild;
printf("%c ",p->data);
}
p = p->rchild;
}
return OK;
}