在之前的二叉树结点结构中,我们使用一个data存放数据,然后分别有一个指向左子树的指针lchild和指向右子树的指针rchild,但是它还是有缺陷的:
- 浪费空间,如下图所示,有十个指针域没有利用到,在64位机器里就是80字节没有利用上
- 浪费时间:由于只是遵循了一个遍历方式来创建或对结点进行访问,我们访问任何一个结点的时间复杂度都是O(n),知道一个结点,也不能访问其前驱或者后继
基于此,我们队二叉树的结点结构进行扩容,如下图所示:
- ltag为0时指向该结点的左孩子,为1时指向该结点的前驱
- rtag为0时指向该结点的右孩子,为1时指向该结点的后继
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef char ElemType;
/*
线索存储标志位
Link:表示指向左右孩子的指针
Thread:表示指向前驱后继的线索
*/
typedef enum {
Link = 0,
Thread
}PointerTag;
typedef struct BiThrNode{
ElemType data;
struct BiThrNode *lchild;
struct BiThrNode *rchild;
PointerTag ltag;
PointerTag rtag;
}BiThrNode,*BiThrTree;
#pragma mark ---- 创建一棵二叉树 ---
//创建一棵二叉树,约定用户遵照前序遍历的方式输入数据
Status createBiThrTree(BiThrTree *T){
ElemType c;
scanf("%c",&c);
if (' ' == c) {
*T = NULL;
return ERROR;
}
*T = (BiThrTree)malloc(sizeof(BiThrNode));
(*T)->data = c;
//先把索引都设置为Link
(*T)->ltag = Link;
(*T)->rtag = Link;
createBiThrTree(&((*T)->lchild));
createBiThrTree(&((*T)->rchild));
return OK;
}
#pragma mark ---中序遍历线索化---
//全局变量,始终指向刚刚访问过的结点
BiThrTree pre;
//中序遍历线索化
Status InThreading(BiThrTree T){
if (T) {
//递归左孩子线索化
InThreading(T->lchild);
//如果左孩子为空,存储前驱结点
if (!(T->lchild)) {
//更改标记
T->ltag = Thread;
//指向前驱
T->lchild = pre;
}
//如果右孩子为空,存储后继结点
if (!(pre->rchild)) {
//更改标记
pre->rtag = Thread;
//指向后继
pre->rchild = T;
}
pre = T;
//递归右孩子线索化
InThreading(T->rchild);
return OK;
}
return ERROR;
}
///创建头结点,并中序遍历二叉树
void inOrderThreading(BiThrTree *p,BiThrTree T){
*p = (BiThrTree)malloc(sizeof(BiThrNode));
//左孩子用于指向二叉树
(*p)->ltag = Link;
//右孩子用于指向前驱,则构成了一个循环链表
(*p)->rtag = Thread;
//先让头结点右孩子指向本身
(*p)->rchild = *p;
if (T) {
//非空树,左孩子指向树的根节点
(*p)->lchild = T;
pre = *p;
InThreading(T);
pre->rchild = *p;
pre->rtag = Thread;
(*p)->rchild = pre;
} else {
//空树,左孩子指向自身
(*p)->lchild = *p;
}
}
void visit(BiThrTree p){
printf("data:%c,ltag:%d,rtag:%d",p->data,p->ltag,p->rtag);
}
//中序遍历二叉树,非递归
void inCorderTraverse(BiThrTree T){
BiThrTree p;
p = T->lchild;
while (p != T) {
while (p->ltag == Link) {
p = p->lchild;
}
visit(p);
while (p->rtag == Thread && p->rchild != T) {
p = p->rchild;
visit(p);
}
}
}
int main(){
BiThrTree P,T = NULL;
createBiThrTree(&T);
inOrderThreading(&P, T);
printf("中序遍历输出结果为 ");
inCorderTraverse(P);
return 0;
}