概念
在之前我们使用链式存储方式定义二叉树时,只从单一结点上看是无法知道该结点有无前驱或者后继结点,而且这种传统方式会导致产生大量的空指针(每个叶子结点都有两个空指针,度为1的结点都有一个空指针)。
所以,我们可以将这些空指针利用起来,如果为空,就让它们指向该结点的前驱结点或者后继结点。一方面提升了遍历查找的速度,另一方面也可以解决空指针太多的问题。这种定义的二叉树就叫做线索二叉树。
定义和结点结构
在线索二叉树中,如果一个节点左孩子结点指针lchild为空,则让lchild指向该结点的前驱结点;如果右孩子结点指针为空,则让rchild指向该结点的后继结点。
此外,结点结构还需要加上两个标识变量ltag和rtag,用来表示lchild和rchild此时所指向结点的意思,如下所示:
- 当ltag=0,表示此时lchild指向左孩子结点;
- 当ltag=1,表示此时lchild指向前驱结点;
- 当rtag=0,表示此时rchild指向右孩子结点;
- 当rtag=1,表示此时rchild指向后继结点。
C++代码实现如下:
struct node_bit_th {
int data,ltag,rtag;
node_bit_th *lchild,*rchild;
};
线索二叉树的遍历
以中序遍历为例,在线索二叉树中,寻找一个结点的后继结点和传统二叉树不同:在传统的二叉树中,只需要依次找到其后继结点直到后继为空,即可实现遍历;而在线索二叉树中,首先看该结点的rtag,如果为值为1,则rchild指向其后继,如果为值为0,则右孩子结点的左孩子结点为后继结点。因此,我们可以分步实现线索二叉树的中序遍历。
node_bit_th *firstNode (node_bit_th *t){
while(t->ltag==0)
t=t->lchild;
return t;
}
node_bit_th *nextNode (node_bit_th *t){
while(t->rtag==0)
return firstNode(t->rchild);
return t->rchild;
}
void midOrder (node_bit_th *t){
for(node_bit_th *p=firstNode(t);p!=NULL;p=nextNode(p))
getx(p);
}