线索二叉树
- 在二叉树的前、中、后序三种遍历出来的树的结点,将其每一种遍历出现的结果换个角度将其排列成一个线性序列,再细看,这些这些线性序列中的每一个元素(结点)都有且仅有一个前驱结点和后继结点。而且更重要的是二叉树的每个叶子结点的左右指针都是空的,是不是觉得不够节约,那么综合上述及其他因素,就有了线索二叉树。
- 先看看原始的二叉树的图
- 讲一讲二叉树某个节点的前驱或者后继节点;比如上图二叉树中序遍历结果为 A B D E C F G ,将这七个节点排列成一个线性序列,那么如 B 的前驱是 A ,后继是 D ;以此类推。
- 假如要得到某个节的前驱或者后继节点;我们只从普通二叉树(第一张图)中某个节点来获得它的前驱或后继,但是,普通二叉树遍历的每个节点是没有备注前驱和后继关系的,所以需要间接得到,也就是只能将整个二叉树遍历一遍才能得到需要的前驱或后继;此时线索二叉树就产生了(样例如图二),将普通二叉树线索化,也就是将二叉树的节点之间建立了前驱和后继关系。
- 总的来说,根据线索二叉树来获得某个节点的前驱或后继节点,是易如反掌的事。
直接上代码(此线索二叉树是有头节点的)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum
{
Link,
Thread
}PointTag; //Link=0 表示指向左右孩子指针 ; Thread=1 表示指向前驱或后继的线索
//Link=0 means pointing to the left and right child pointer
//Tread=1 means pointing to predecessor or successor
typedef char ElemType;
typedef struct BiThrTNode
{
ElemType data;
struct BiThrTNode *lchild;
struct BiThrTNode *rchild;
PointTag LTag; //左右标志
PointTag RTag; //left and right sign
}BiThrTNode, *BiThrTree;
typedef BiThrTree SElemType;
typedef struct StackNode
{
SElemType sdata;
struct StackNode *next;
}StackNode, *LinkStackNode;
typedef struct
{
LinkStackNode top;
}LinkStack;
LinkStack S;
void init_Stack(LinkStack *S)
{
S->top = NULL;
}
void push_Stack(LinkStack *S, SElemType e)
{
LinkStackNode sNew = (LinkStackNode)malloc(sizeof(StackNode));
sNew->sdata = e;
sNew->next = S->top;
S->top = sNew;
}
void pop_Stack(LinkStack *S, SElemType &e)
{
LinkStackNode p = S->top;
if (p == NULL)
{
return;
}
e = p->sdata;
S->top = p->next;
free(p);
p = NULL;
}
SElemType get_Top(LinkStack S)
{
if (S.top != NULL)
{
return S.top->sdata;
}
else
{
return NULL;
}
}
bool isEmpty(LinkStack S)
{
if (S.top == NULL)
{
return true;
}
else
{
return false;
}
}
void creat_Tree(BiThrTree &T)
{
init_Stack(&S);
ElemType node[100]={};
scanf("%s", node);
int len = strlen(node);
BiThrTree tn1, tn2;
bool flag;
if (node[0] != '#')
{
tn1 = (BiThrTree)malloc(sizeof(BiThrTNode));
tn1->data = node[0];
tn1->lchild = tn1;
tn1->LTag = Link;
tn1->rchild = tn1;
tn1->RTag = Link;
T = tn1;
int k = 0;
push_Stack(&S, tn1);
while (!isEmpty(S) && k != len - 1)
{
flag = false;
if (node[++k] != '#')
{
tn2 = (BiThrTree)malloc(sizeof(BiThrTNode));
tn2->data = node[k];
tn2->lchild = tn2;
tn2->LTag = Link;
tn2->rchild = tn2;
tn2->RTag = Link;
flag = true;
}
else
{
tn2 = NULL;
}
tn1 = get_Top(S);
while(tn1->lchild != tn1 && tn1->rchild != tn1)
{
pop_Stack(&S, tn1);
tn1 = get_Top(S);
}
if (tn1->lchild == tn1)
{
tn1->lchild = tn2;
}
else
{
tn1->rchild = tn2;
}
if (flag)
{
push_Stack(&S, tn2);
}
}
}
else
{
T = NULL;
printf("The tree is empty! The tree can`t created!\n");
}
}
//BiThrTree pre;
void InThreading(BiThrTree T, BiThrTree *pre) //递归的二叉树线索化
{
if (T)
{
InThreading(T->lchild, pre);
if (T->lchild == NULL)
{
T->LTag = Thread;
T->lchild = *pre;
}
if ((*pre)->rchild == NULL)
{
(*pre)->RTag = Thread;
(*pre)->rchild = T;
}
*pre = T;
InThreading(T->rchild, pre);
}
}
void UnRe_InTHreadin(BiThrTree T, BiThrTree *pre) //非递归的二叉树线索化
{
init_Stack(&S);
BiThrTree tree = T;
if (!tree)
{
printf("The tree is empty!\n");
}
else
{
while (tree || !isEmpty(S))
{
while (tree)
{
push_Stack(&S, tree);
tree = tree->lchild;
}
pop_Stack(&S, tree);
if (tree->lchild == NULL)
{
tree->LTag = Thread;
tree->lchild = *pre;
}
if ((*pre)->rchild == NULL)
{
(*pre)->RTag = Thread;
(*pre)->rchild = tree;
}
*pre = tree;
tree = tree->rchild;
}
}
}
void In_Head_Threading(BiThrTree &Thrt, BiThrTree T)
{
Thrt = (BiThrTree)malloc(sizeof(BiThrTNode));
if (!Thrt)
{
exit(0);
}
Thrt->LTag = Link;
Thrt->RTag = Thread;
Thrt->rchild = Thrt;
if (!T)
{
Thrt->lchild =Thrt;
return;
}
BiThrTree pre; //设置前驱
pre = Thrt;
Thrt->lchild = T;
// InThreading(T, &pre);
UnRe_InTHreadin(T, &pre);
pre->rchild = Thrt;
pre->RTag = Thread;
Thrt->rchild = pre;
}
void InOrderTraveral(BiThrTree T)
{
BiThrTree 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;
}
}
int main()
{
BiThrTree T;
creat_Tree(T); //非递归先序创建二叉树 Create a non-recursive preprder binary tree
//在线索二叉树中新增一个头节点指向根节点
//Add a header node to the root node in clue binary tree
BiThrTree Tree;
In_Head_Threading(Tree, T);
//遍历线索二叉树 Traveral of the clue binary tree
InOrderTraveral(Tree);
return 0;
}
测试数据:ABD##E##CF##G##