一、概述
由于给定某一次序的遍历序列,在序列中很容易找到前驱和后继,但在二叉树中寻找指定结点的前驱和后继结点不方便,而且n个结点具有n+1个空链域,因此可以将其利用起来,用来记录该结点的前驱和后继信息。
如果某一结点没有左孩子或右孩子,则将其指针指向其前驱或者后继,称指向前驱和后继结点的指针为线索。这个过程称为二叉树的线索化。
二叉树地线索化是指就是按某种次序遍历一遍二叉树,每遍历到一个结点,对其建立线索。因此就对应有三种线索二叉树。
注: 此处的前驱和后继均是相对于遍历序列(前,中,后序)而言的。
二、原理
在结点中在增加两个标志位,ltag和rtag,如果ltag和rtag为1,则代表相应的左右孩子为线索,如果为0,则表示指向孩子。再设置一个pre指针,用来指向当前结点p的前驱结点,在遍历过程中,如果p的左指针域为空,则将p的左指针指向pre,然后令ltag为1,pre=p;如果pre所指的结点右指针为空,则令其指向p,即指向它的后继(如果存在的话),并让rtag=1。另外需要注意的是对最后一个结点要单独处理,因为它已没有后继结点。
三、代码实现
1、结点定义
typedef int ElemType;
typedef struct ThreadBiTNode {//结点定义
ElemType data;
struct ThreadBiTNode *lchild;
struct ThreadBiTNode *rchild;
int ltag, rtag; //左右线索标志,初始值均为0;
} ThreadBiTNode, *ThreadBiTree;
ThreadBiTNode *pre = NULL;//指向结点前驱
2、先序线索二叉树
基于先序遍历,在遍历的途中,为每个结点建立线索。需要注意的是,在先序遍历中,先访问到的是根,如果此时为一个结点建立了左线索,说明该结点无左孩子,应停止遍历左子树,转向遍历右子树,否则会形成环路。
void CreateThreadBiTNode(ThreadBiTNode *P) { //为当前结点建立线索
if (P == NULL)
return;
if (P->lchild == NULL) {//建立前驱线索
P->lchild = pre; //左孩子指向其前驱
P->ltag = 1; //左孩子为线索
}
if (pre != NULL && pre->rchild == NULL) {//建立后继线索
pre->rchild = P;//后继为P
pre->rtag = 1;//右孩子为线索
}
pre = P;//更新前驱
}
void PreThread(ThreadBiTree T) { //先序遍历建立线索
if (T != NULL) {
CreateThreadBiTNode(T);
if(T->ltag==0)//存在左孩子
PreThread(T->lchild);
PreThread(T->rchild);
}
}
void CreatePreThreadBiTree(ThreadBiTree &T) { //主过程,建立先序线索二叉树
if (T != NULL) {
PreThread(T);
pre->rchild = NULL; //对最后一个点单独处理
pre->rtag = 1;
}
}
3、中序线索二叉树
基于中序遍历,在遍历的途中,为每个结点建立线索。
void CreateThreadBiTNode(ThreadBiTNode *P) { //为当前结点建立线索
if (P == NULL)
return;
if (P->lchild == NULL) {//建立前驱线索
P->lchild = pre; //左孩子指向其前驱
P->ltag = 1; //左孩子为线索
}
if (pre != NULL && pre->rchild == NULL) {//建立后继线索
pre->rchild = P;//后继为P
pre->rtag = 1;//右孩子为线索
}
pre = P;//更新前驱
}
void InThread(ThreadBiTree T) { //中序遍历建立线索
if (T != NULL) {
InThread(T->lchild);
CreateThreadBiTNode(T);
InThread(T->rchild);
}
}
void CreateInThreadBiTree(ThreadBiTree &T) { //主过程,建立中序线索二叉树
if (T != NULL) {
InThread(T);
pre->rchild = NULL; //对最后一个点单独处理
pre->rtag = 1;
}
}
4、后序线索二叉树
基于后序遍历,在遍历的途中,为每个结点建立线索。
void CreateThreadBiTNode(ThreadBiTNode *P) { //为当前结点建立线索
if (P == NULL)
return;
if (P->lchild == NULL) {//建立前驱线索
P->lchild = pre; //左孩子指向其前驱
P->ltag = 1; //左孩子为线索
}
if (pre != NULL && pre->rchild == NULL) {//建立后继线索
pre->rchild = P;//后继为P
pre->rtag = 1;//右孩子为线索
}
pre = P;//更新前驱
}
void PostThread(ThreadBiTree T) { //后序遍历建立线索
if (T != NULL) {
PostThread(T->lchild);
PostThread(T->rchild);
CreateThreadBiTNode(T);
}
}
void CreatePostThreadBiTree(ThreadBiTree &T) { //主过程,建立后序线索二叉树
if (T != NULL) {
PostThread(T);
pre->rchild = NULL; //对最后一个点单独处理
pre->rtag = 1;
}
}