线索二叉树
遍历二叉树就是以一定的规则将二叉树中的结点排列成一个线性序列,从而得到二叉树结点的各种遍历序列。其实质就是对一个非线性结构进行线性化操作,使在这个访问序列中每一个结点(除了第一个和最后一个)都有一个直接前驱和直接后继。
在二叉树的链式存储中,只能体现出父子关系,不能直接得到结点在遍历中的前驱和后继。前边提到,在有N个结点的二叉树中,有N+1个空指针域,如果利用这些空指针域存放指向其前驱或者后继的地址,那么就可以方便的运用某些二叉树操作算法。这些指针就是线索,引入线索二叉树就是为了加快查找结点前驱和后继的速度。
线索二叉树的结点结构如下:
- 如果没有左子树,lchild指向前驱结点;如果没有右子树,rchild指向后继结点。
- ltag和rtag表示指向的是子节点还是前驱(后继)结点。
- ltag=0表示lchild指向的是左孩子;ltag=1表示lchild指向的是前驱。
- rtag=0表示rchild指向的是右孩子;rtag=1表示rchild指向的是后继。
存储结构如下:
typedef struct ThreadNode{
ElementType data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag; // 标识是否是线索,如果是线索,则为1
}ThreadNode,*ThreadTree;
上面说的前驱和后继,树哪里有前驱和后继?这里的前驱和后继是相对于遍历说的。二叉树先序遍历、中序遍历、后序遍历得到一个线性序列,所以二叉线索树就可以分为中序线索二叉树、先序线索二叉树和后序线索二叉树。
主要程序如下:
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
/*
线索存储标志位
Link(0):表示指向左右孩子的指针
Thread(1):表示指向前驱后继的线索
*/
typedef enum {Link, Thread} PointerTag;
typedef struct BiThrNode{
ElemType data;
struct BiThrNode *lchild, *rchild;
PointerTag ltag;
PointerTag rtag;
}BiThrNode, *BiThrTree;
//全局变量,始终指向刚刚访问过的节点
BiThrTree pre;
//创建一棵二叉树,约定用户遵照前序遍历方式输入数据
void createBiThrTree(BiThrTree *T){
char c;
scanf("%c", &c);
if('#' == c){
*T = NULL;
}else{
*T = (BiThrNode*)malloc(sizeof(BiThrNode));
(*T)->data = c;
(*T)->ltag = Link;
(*T)->rtag = Link;
createBiThrTree(&(*T)->lchild);
createBiThrTree(&(*T)->rchild);
}
}
//中序遍历线索化
void inThreading(BiThrTree T){
if(T){
inThreading(T->lchild);//递归左孩子线索华
//节点处理
if(!T->lchild){//处理前驱,什么时候能知道前驱,就是当前节点的时候,
//已经知道前一个是pre了,所以直接tag=thread,lchild=pre
T->ltag = Thread;
T->lchild = pre;
}
if(pre!=NULL && !pre->rchild){//处理后继,什么时候处理后继,只有访问到下一个的时候,
//才能知道下一个是谁,因为当访问下一个的时候,下一个是T,让pre的rchild指向T就好
pre->rtag = Thread;
pre->rchild = T;
}
pre = T;
inThreading(T->rchild);//递归右孩子线索华
}
}
//中序遍历线索二叉树---非递归
void InOrderThreading(BiThrTree T){
BiThrTree p = T;
while(p != NULL){
//当ltag == Thread时,循环到中序序列第一个节点
while(p->ltag == Link){
p = p->lchild;
}
printf("%c ", p->data);
while(p->rtag == Thread && p->rchild != NULL){
p = p ->rchild;
printf("%c ", p->data);
}
p = p->rchild;
}
}
int main(){
BiThrTree T = NULL;
createBiThrTree(&T);
inThreading(T);
pre->rtag = Thread;
InOrderThreading(T);
return 0;
}