线索二叉树

来源:互联网 发布:免费宠物店收银软件 编辑:程序博客网 时间:2024/06/05 20:16

线索二叉树方便了寻找前驱和后继

如何构造前面那棵二叉树的中序线索二叉树呢?假定线索二叉树采用链式存储结构,也就是要构造这棵二叉树的中序线索链表。

第一步:首先为二叉树中的每个结点都建立一个BiThrNode类型的结点,若某结点有左孩子,就令其左指针域指向左孩子结点,否则,就暂时让它为空;若某结点有右孩子,就令其右指针域指向右孩子结点,否则,就暂时让它为空。

第二步:为了便于对线索链表进行操作,和单链表一样,为二叉树的线索链表也增加一个头结点,并规定:头结点的左指针域指向二叉树的根结点,即头结点的左指针域是一个指针;头结点的右指针域指向中序列中的最后一个结点,即头结点的右指针域是一个线索,暂时令其为空。再令,若二叉树遍历序列中的第一个结点的左指针域为空,则让其指向线索链表的头结点,即把头结点看成是第一个结点的直接前驱;若二叉树遍历序列中的最后一个结点的右指针域为空,则也让其指向线索链表的头结点,即把头结点看成是最后一个结点的直接后继;      总之一句话,将头结点看成是第一个结点的直接前驱,同样看成是最后一个结点的直接后继。

第三步:若某结点的左指针域为指针,则令左标志为0,若某结点的右指针域为指针,则令右标志为0。反之,若某结点的左指针域为空,即将来成为线索,则令左标志为1,若某结点的右指针域为空,即将来成为线索,则令右标志为1

第四步:按照中序遍历序列中结点的次序关系和第二步中的规定修改空指针,使其指向它的前驱结点或后继结点。

再来看一下上述二叉树的先序线索链表和后续线索链表的构造过程。

这里需要特别注意的是,若二叉树为空,则它对应的线索链表中只含有一个头结点,且规定头结点的左指针域指向其自身,即左指针域仍为指针;右指针域为空,即右指针域仍为线索,且在空线索链表中,右线索也指向头结点自身。空二叉树对应的线索链表如下所示。



<span style="font-size:14px;">//0 为link,1为thread#include <iostream>#include <stdlib.h>using namespace std;typedef struct node{    char data;    struct node* lchild;    struct node* rchild;    int ltag,rtag;}bitnode,*bitree;void create(bitree &bt){    char data;    cin>>data;    if(data=='#')        bt=NULL;    else    {        bt=(bitree)malloc(sizeof(bitnode));        bt->data=data;        create(bt->lchild);        create(bt->rchild);    }}void inthread(bitree &bt,bitree &pre)//二叉树中序线索化{    bitree &p=bt;    if(p!=NULL)    {   inthread(p->lchild,pre);        if(p->lchild==NULL)        {            p->ltag=1;            p->lchild=pre;        }        else            p->ltag=0;        if(pre->rchild==NULL)        {            pre->rtag=1;            pre->rchild=p;        }        else            pre->rtag=0;        pre=p;        inthread(p->rchild,pre);    }}void Inorderthread(bitree &bt){    bitree head,pre;    head=(bitree)malloc(sizeof(bitnode));//对头结点进行初始化    head->ltag=0;    head->rtag=1;    head->rchild=head;    if(bt==NULL)//如果是空树则左指针回指        head->lchild=head;    else    {        head->lchild=bt;        pre=head;        inthread(bt,pre);//pre为最后一个结点        pre->rtag=1;//对最后一个结点初始化        pre->rchild=head;        head->rchild=pre;        head->rtag=1;    }    bt=head;//使bt指向头结点}/*******************************//*若p结点的右子树为空,则返回p结点右线索指向的结点 即p->rchild;/*若p结点的右子树不为空,则p的后继一定是p的右子树中序遍历的第一个结点/******************************/bitree getnext(bitree bt){    bitree q;    if(bt->rtag==1)//如果求的该结点有右线索则直接返回右线索指向的结点        return bt->rchild;    else    {        q=bt->rchild;//否则q为右子树根结点        while(q->ltag==0)//一直到当q结点的左子树的最下面        {            q=q->lchild;        }        return q;    }}bitree find(bitree &bt,char e){        bitree p;    if(bt==NULL)        return NULL;    if(bt->data==e)        return bt;    p=find(bt->lchild,e);    if(p!=NULL && p->data==e)        return p;    p=find(bt->rchild,e);    if(p!=NULL && p->data==e)        return p;    return NULL;}void inthreadtraverse(bitree bt){    bitree p=bt->lchild;//p为根结点    while(p!=bt)//当p结点不为头结点的时候    {        while(p->ltag==0)//一只寻找到左子树的最左边的结点使p指向中序遍历最左边的结点        {            p=p->lchild;        }        cout<<p->data;//输出该结点的值        while(p->rtag==1 && p->rchild!=bt)//当该结点有右线索,且右线索不是头结点的时候        {            p=p->rchild;//一值往右遍            cout<<p->data;//输出        }        //当p所指结点的rchild指向的是孩子结点而不是线索时,p的后继应该是其右子树的最左下的结点,即遍历其右子树时访问的第一个节点        p=p->rchild;    }}int main(){    bitree bt,p;    create(bt);    //bt=bt->lchild;    //cout<<bt->data    p=find(bt,'G');    Inorderthread(bt);    p=getnext(p);    cout<<p->data;}</span>


0 0