从0开始学习数据结构-树与二叉树-线索二叉树②

219 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

线索二叉树的利用

建立了线索二叉树以后,可以方便地找到指定结点在某种遍历序列中的直接前驱结点或直接后继结点,而不必再对二叉树重新进行遍历。另外,在线索二叉树上进行某种遍历要比在一般二叉树上进行这种遍历要简单得多,无论是递归算法还是非递归算法,都不会涉及堆栈。

1.在中序线索二叉树中确定地址为x结点的直接前驱结点

确定过程有如下的规律:

①当x->lbit=0;(或x->lchild为负值)时,x->lchild所指的结点就是x的直接前驱结点。

②当x->lbit=1(或x->lchild为正值)时,说明x结点有左子树,它的直接前驱结点应该是x结点的左子树中的最右边那个结点,即顺着x结点左子树的根的右指针链往下寻找,直到某结点的rchild域是线索为止。此时,该结点就是x所指结点的直接前驱结点。

在下面的算法中,当算法结束时,指针变量s指向x所指结点的直接前驱结点。

//在中序线索二叉树中确定地址为x结点的直接前驱结点
TBTREE INPRIOR(TBTREE x){
    TBTREE s;
    s=x->lchild;
    if(x->lbit==1)
        while (s->rbit == 1)
            s=s->rchild;
    return s;
}

2.在中序线索二叉树中确定x所指结点的直接后继结点

若结点的右指针域为线索,则右指针域中的地址直接指出了该结点的直接后继结点。若二叉树中分支结点的右指针域为指针,则无法由此得到直接后继结点的信息。然而,根据中序遍历的规律,某个结点的直接后继结点应该是遍历其右子树时访问的第1个结点,即右子树中最左下的那个结点。

于是,在中序线索二叉树中确定存储地址为x结点的直接后继结点的规律可以描述如下:

  • 当x->rbit=0(或x->rchild为负值)时,x->rchild指出的结点就是x的直接后继结点。
  • 当x->rbit=1(或x->rchild为正值)时,沿着x结点右子树的根的左指针链往下找,直到某结点的lchild域为线索。此时,该结点就是x结点的直接后继结点。

下面是相应算法。算法结束时,指针变量s指向x结点的直接后继结点。

//2.在中序线索二叉树中确定x所指结点的直接后继结点
TBTREE INSUCC(TBTREE x){
    TBTREE s;
    s=x->rchild;
    if(x->rbit == 1)
        while (s->lbit==1)
            s=s->lchild;
    return s;
}

3.利用线索二叉树遍历二叉树

利用线索二叉树进行遍历则可以不设置堆栈,而且算法十分简洁,只要首先找到序列中的第1个结点,然后依次找到结点的直接后继结点,直至某结点的直接后继结点为空为止。

下面给出对中序线索二叉树进行中序遍历的算法。算法中指针HEAD指向线索二叉树的头结点。

void VISIT(TBTREE p){
    printf("%C\t",p->data);
}

//3.利用线索二叉树遍历二叉树(中序线索)
void TINORDER(TBTREE HEAD){
    TBTREE p = HEAD;
    while (1){
        p= INSUCC(p);
        if(p==HEAD)
            break;
        VISIT(p); //访问p所指的结点
    }
}

二叉树的线索化

对二叉树的线索化,就是把二叉树的二叉链表存储结构中结点的所有空指针域改造成指向某结点在某种遍历序列中的直接前驱结点或直接后继结点的过程,因此,二叉树的线索化过程只能在对二叉树的遍历过程中进行。