线索二叉树

Posted on 2020-04-23 09:55  金色的省略号  阅读(316)  评论(0编辑  收藏  举报

  二叉树,二叉链表中,有N个结点,2N个指针,N+1个空指针,把空指针加以利用可以线索结点的前驱或后继,这就形成了线索二叉树;无左孩子的空指针,指向该结点前驱,无右孩子的空指针,指向该结点的后继;这样,就可以不用递归或栈就可以遍历二叉树; 

  1、线索二叉树的概念,指向遍历序列前驱、后继结点的指针称为线索;把空指针修改为线索的过程称为线索化;经过线索化的二叉树称为线索二叉树;

  2、线索二叉树的结构,为了区分指针是否为线索,需要修改结点结构,增加左右标志域Ltag,Rtag用于判断;可以设定Ltag为0指示是结点的左孩子,为1指示是结点的前驱,Rtag为0指示是结点的右孩子,为1指示是结点的后继;

  3、线索二叉树的种类,依据二叉树遍历的不同,存在三种不同的线索二叉树,先序线索二叉树,中序线索二叉树,后序线索二叉树;二叉树的线索化,是按三种不同遍历的序列进行

  4、二叉树线索化的实现,在遍历的过程中,设定二个指针,一个指向当前结点的指针p,一个指向当前结点的前驱结点的指针pre,p与pre是动态变化的一对指针,pre是p的前驱,p是pre的后继,这一点非常重要,判断当前结点(p指向)的左孩子指针是否为空,如为空,指针pre修改当前结点左孩子指针;判断前驱结点(pre指向)的右孩子指针是否为空,如为空,指针p修改前驱结点(pre指向)的右孩子指针;左右孩子指针为空,别忘了修改Ltag或Rtag为1;p判断左孩子,pre判断右孩子;

/* 中序遍历二叉树 线索化 */
BinTree pre = NULL;    /* 定义全局变量pre指针 */
void InThread(BinTree p)
{
    if(p != NULL)
    {
        InThread(p-Left); 
        
        if(p->Left==NULL){   /* 当前结点的左孩子为空 */
            p->Left = pre;   /* pre修改当前结点左孩子指针 */
            p->Ltag = 1;     /* 左孩子指针为线索 */
        }
        if(pre != NULL && pre->Right == NULL){
            pre->Right = p;  /* 当前结点的前驱结点的右孩子为空 */
            pre->Rtag = 1;
        }
        pre = p; /* 更新pre */
        
        InThread(p->Right);
    }
}

  5、遍历线索二叉树依据不同的线索二叉树访问遍历的第一个结点;寻找并访问当前结点的后继结点,直至所有的结点被访问;

  中序遍历的第一个结点是树中处于最左下端的结点,从根沿着左孩子指针找到没有左孩子的结点即可;中序遍历的后继结点,结点若无右孩子,Right指针指向的是其后继,若有右孩子,右子树中最左下端结点即为其后继;在中序线索树中找结点的直接前驱,是找左子树中最右下端的结点,左子树为线索的可以直接找到;

/* 寻找中序遍历的第一个结点 */
BinTree InFirst(BinTree Bt)
{
    BinTree p = Bt;
    if(!p) return NULL;
    while(p->Ltag == 0)
        p = p->Left;
    return p;
}
 1 /* 寻找中序遍历的当前结点的后继结点 */
 2 BinTree InNext(BinTree p)
 3 {
 4     BinTree Next = NULL;
 5     if(p->Rtag == 1) Next = p->Right;
 6     else{
 7         for(BinTree q = p->Right; q->Ltag == 0; q = q->Left);
 8         Next = q;
 9     }
10     return Next;
11 }
/* 中序线索二叉树的遍历算法 */
void InOrder(BinTree Bt)
{
    BinTree p = NULL;
    p = InFirst(Bt);
    while(p)
    {
        visit(p);
        p = InNext(p);
    }
}