1. 慨念
传统的链式存储仅体现一种父子关系,不能直接得到结点在遍历中的前趋或后继。到这种二叉链表表示的二叉树中存在大量的空指针,而线索二叉树就是将这些空域利用起来。存放其直接前趋或者后继的指针。
ltag | lchild | data | rchild | rtag |
---|
在二叉树线索化时,通常规定:若无左子树,令lchild指向其前趋结点; 若无右子树,令rchild指向其后继结点。(这里的前趋结点和后继结点是相对于是使用前序,中序,后序而言)
2. 线索二叉树的构造
对二叉树的线索化,实质上就是遍历一次二叉树,只是在遍历的过程中,检查当前结点左,右指针域是否为空,若为空,将它们改为指向前趋结点或后继结点的线索。
以中序线索二叉树的建立为例:
void InThread(ThreadTree &p, ThreadTree &pre){ //&pre用来表示各结点访问的前后关系
//使用中序遍历对二叉树线索化的递归算法
if(p != NULL){
InThread(p->lchild,pre); //递归,线索化左子树
if(p->lchild == NULL){ //左子树为空,建立前趋线索
p->lchild = pre;
p->ltag = 1;
}
if(pre!=NULL&&pre->rchild==NULL){ //注意,上面是对p的前趋判断。这里对pre的后继判断,不是操作同一结点
pre->rchild = p; //建立前趋结点的后继线索
pre->rtag = 1;
}
pre=p; //标记当前结点成为刚刚访问过的结点
InThread(p->rchild,pre); //递归,线索化右子树
}//if(p!=NULL)
}
void CreateInThread(ThreadTree T){
ThreadTree pre = NULL;
if(T!=NULL){ //非空二叉树,线索化
InThread(T,pre); //线索化二叉树
pre->rchild=NULL; //处理遍历的最后一个结点
pre->rtag = 1;
}
}
3. 线索二叉树的遍历
ThreadNode *Firstnode(ThreadNode *p){ //求中序线索二叉树中中序序列下的第一个结点
while(p->ltag==0) p=p->lchild; //最左下结点
return p; //标志为1,则返回p
}
TreadNode *Nextnode(TreadNode *p){
if(p->rtag==0) return Firstnode(p->rchild);
else return p->rchild; //rtag=1,直接返回后继线索
}
void Inorder(TreadNode *T){
for(TreadNode *p=Fristnode(T);p!=NULL;p=Nextnode(p))
visit(p);
}