线索二叉树

一、线索二叉树的基本概念

       传统的链式存储结构仅能体现一种父子关系,不能直接得到结点在遍历中的前驱或后继。我们发现在二叉链表表示的二叉树中存在大量的空指针,如果利用这些空链域存放指向其直接前驱或后继的指针,则可以更方便地运用某些二叉树操作算法。引入线索二叉树是为了加快查找结点前驱和后继的速度。

       在有n个结点的二叉树中,有n+1个空指针。

       在线索二叉树中,通常规定:若无左子树,令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点。同时增加两个标志域表明当前指针域所指对象是向左(右)子结点还是指向直接前驱(后继)。

       图示如下:

       标志域的含义如下:

       线索二叉树的存储结构描述如下:      

typedef struct ThreadNode{
    ElemType data;                         //数据元素
    struct ThreadNode *lchild, *rchild;    //左、右孩子指针
    int ltag, rtag;                        //左、右线索标志
}ThreadNode, *ThreadTree;

       这种结点结构构成的二叉链表作为二叉树的存储结构,称为线索链表,其中指向结点前驱和后继的指针称为线索。加上线索的二叉树称为线索二叉树。对二叉树以某种次序遍历使其变为线索二叉树的过程称为线索化。

 

二、线索二叉树的构造

       对二叉树的线索化,就是遍历一次二叉树,然后在其过程中,检查当前结点左、右指针域是否为空,若为空,将它们改为指向前驱结点或后继结点的线索。

       以中序线索二叉树的建立为例,指针pre指向中序遍历时上一个刚刚访问过的结点,用它来表示各结点访问的前后关系。如下图所示:

       通过中序遍历对二叉树线索化的递归算法如下:      

void InThread(ThreadTree &p, ThreadTree &pre)
{                                              //中序遍历对二叉树线索化的递归算法
    if(p!=NULL)
    {
        InThread(p->lchild, pre);              //递归,线索化左子树
        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);                  //递归,线索化右子树
    }
}

       通过中序遍历建立中序线索二叉树的主过程算法如下:    

void CreateInThread(ThreadTree T)
{
    ThreadTree pre=NULL;
    if(T!=NULL)                    //非空二叉树,线索化
    {
        InThread(T, pre);          //线索化二叉树
        pre->rchild=NULL;          //处理遍历的最后一个结点
        pre->rtag=1;
    }
}

         有时仿照线性表的存储结构,在二叉树的线索链表上也添加一个头结点,并令其lchild域的指针指向二叉树的根结点,令其rchild域的指针指向中序遍历时访问的最后一个结点;反之,令二叉树中序序列中的第一个结点的lchild域的指针和最后一个结点的rchild域的指针均指向头结点。如下图所示:

 

三、线索二叉树的遍历

       中序线索化二叉树主要是为访问运算服务的,这种遍历不再需要借助栈,因为它的结点中隐含了线索二叉树的前驱和后继信息。不含头结点的线索二叉树的遍历算法如下:

1.求中序线索二叉树中中序序列下的第一个结点:    

ThreadNode *Firstnode(ThreadNode *p)
{
    while(p->ltag==0)      p=p->lchild;         //最左下结点(不一定是叶结点)
    return p;
}

2.求中序线索二叉树中结点p在中序序列下的后继结点:     

ThreadNode *Nextnode(ThreadNode *p)
{
    if(p->rtag==0) return Firstnode(p->rchild);
    else return p->rchild;  //rtag==1直接返回后继线索
}

3.利用上面两个算法,可以写出不含头结点的中序线索二叉树的中序遍历的算法:   

void Inorder(ThreadNode *T)
{
    for(ThreadNode *p=Firstnode(T); p!=NULL; p=Nextnode(p))
        visit(p);
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值