数据结构-线索二叉树

166 阅读2分钟

概念

在之前我们使用链式存储方式定义二叉树时,只从单一结点上看是无法知道该结点有无前驱或者后继结点,而且这种传统方式会导致产生大量的空指针(每个叶子结点都有两个空指针,度为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);
}