线索二叉树

今天刷题的时候发现结构算法1800上的题关于线索二叉树的没有考很深,但是如果对整个基础算法没有很好地把握的话做题还是有几个点有点疑惑,于是把整个完整线索化整理了一下,包括前中后序的差别,以中序为例(毕竟递归只是换换执行顺序),把过程整个推了一遍终于把递归的逻辑理通了。

线索化的本质是把非线性结构变成线性结构,利用二叉链表的空链域存放指向直接前驱和后继的指针。
熟悉了这个结构以后解决对应得问题也变得很轻松了
几个经典问题:关于某结点的前驱后继问题,空的链域有几个,线索数,类似后序非递归遍历的,后序线索树的遍历仍需要栈的支持,联考还考过符合后续线索树定义的图像,如果对过程很熟悉可以用来验证答案。

需要注意的是后序线索二叉树不能有效解决求后续后继的问题,仍应按常规办法寻找。

存储结构

typedef struct ThreadNode{
        int data;//数据
        struct ThreadNode *lchild,rchild;
        int ltag, rtag;
}ThreadNode, *ThreadTree;

其中引入了标志域:
Ltag 为0表示lchild域指向左孩子
Ltag 为1表示lchild域指向直接前驱
Rtag 为0表示rchild域指向右孩子
Rtag 为1表示rchild域指向直接后继

void InThread(ThreadTree &p, ThreadTree &pre)
{
        //inorder so we start from left tree :)
        if(p!=NULL)
        {
            InThread(p->lchild, pre);
            //when first iterator pre =null
            if(p->lchild == NULL){
                p->lchild = pre;
                p->ltag = 1;
            }
            if(pre!=NULL && pre->rchild == NULL){
                pre->rchild = p;
                pre->rtag = 1;
            }
            pre = p;
            InThread(p->rchild, pre);
            //Then we finished right side
        }
        
}

递归的算法看起来很简单但是如果真的走一遍还是会发现很多问题的,所以画了个图


初始状态

让我们进入第一次迭代,递归的执行左移的操作,此时pre始终为空,终于我们来到了最左边的结点~
最左结点的lchild肯定为空啦,所以将他的前驱lchild设为pre,但此时pre为NULL,于是lchild域置空,ltag为1,标记它是一条线索。


IMG_8778.JPG

IMG_8773.JPG

而此时pre为NULL跳过第二段判定,令pre = p

进入当前循环的右子树部分,p右移到最右,此时的p左子树为空,pre指向我们刚才搞完的B结点,所以把p的直接前驱=pre所指结点,pre !=null 但 pre的rchild != null所以pre 指向 D结点 结束


IMG_8774.JPG

此时第一次迭代中的第一条语句才执行完,p仍指向root
其lchild不为空,但此时pre!=null && pre->rchild == null了
于是我们将pre所指向结点的rchild指向当前的p,
继续pre = p,并开始递归线索化右子树!
IMG_8775.JPG

p右移到最右结点(这图好简单),先进入到他的最左结点,此时pre仍在根节点哦,因为当前结点没有lchild,所以前驱设为pre指向结点,即根节点,然后pre就可以名正言顺的指向E结点了
此时C结点的左子树结束
IMG_8776.JPG

lchild不为空跳过,此时pre!=null && rchild == null,pre->rchild = p; pre 指向C结点,因为C无右子树,这个时候A结点的右子树也结束了。


IMG_8777.JPG

再执行完整个InThread之后,我们应把pre指向结点的后继置空,表示整个线索的结束。

你可能感兴趣的:(线索二叉树)