线索化二叉树

                        线索二叉树

基本概念:

  n个结点的二叉链表中共有2n个链域,但只有n-1个有用的非空链域,其余n+1个是空的,利用这n+1个空链域来存放遍历过程中结点的前驱和后继;规定:若结点有左子树,则其LChild指向左孩子,否则LCHild指向前驱;若结点有右子树,则其RChild域指向右孩子,否则指向后继。

  Ltag=0,CHild指向左孩子;Ltag=1,CHild指向遍历的前驱

  Rtag=0,RHild指向左孩子;Rtag=1,RHild指向遍历的前驱

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

算法思想:

  1. 中序线索化采用中序递归遍历算法框架
  2. 加线索的操作就是访问结点的操作
  3. 加线索操作需要利用刚访问的结点与当前节点的关系,因此设置一个指针pre,始终记录刚访问过的结点,操作如下

    a.如果当前遍历结点root的左子域为空,左子域指向pre;

    b.如果前驱pre的右子域为空,则让右子域指向当前遍历结点root;

    c.为下次做准备,访问当前结点root作为下一个访问结点的前驱pre

 

废话不多说了,直接上代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct Tree
{
    int data,Ltag,Rtag;//数据,左右标志 
    struct Tree *LChild,*RChild;//左右孩子指针域 
}Tree,*Trees;
Trees pre=NULL;

void InitTree(Trees *boot)//初始化二叉树,只有一个根节点,无左右孩子 
{
    *boot=(Trees)malloc(sizeof(Tree));
    (*boot)->LChild=(*boot)->RChild=NULL;
    (*boot)->Ltag=(*boot)->Rtag=0; 
}

void CreateTree(Trees &boot)//创建二叉树,具体操作参考上一篇《树与二叉树》 
{
    int ch;
    scanf("%d",&ch);
    if(ch==0)
        boot=NULL;
    else
    {
        boot=(Trees)malloc(sizeof(Tree));
        boot->data=ch;
        boot->LChild=boot->RChild=NULL;
        boot->Ltag=boot->Rtag=0;
        CreateTree(boot->LChild);
        CreateTree(boot->RChild);
    }
}
//添加线索 
void InThread(Trees &boot)
{
    if(boot!=NULL)
    {
        InThread(boot->LChild);//线索化左子树 
        if(boot->LChild==NULL)
        {
            boot->Ltag=1;
            boot->LChild=pre;//置前驱线索 
        }
        if(pre!=NULL&&pre->RChild==NULL)
        {
            pre->RChild=boot;
            pre->Rtag=1;
        }
        pre=boot;//当前访问节点为下一个访问节点的前驱 
        InThread(boot->RChild);//线索化右子树 
    }
} 

Trees InOrderThread(Trees &rt)//建头结点 
{
    Trees thrt;
    if(!(thrt=(Trees)malloc(sizeof(Tree))))
    {
        printf("头结点创建失败.\n");
        exit(1);
    }
    
    thrt->Ltag=0;//等于零指向左孩子  1
    thrt->Rtag=1;//等于一指向遍历的前驱 2
    thrt->RChild=thrt;//右回指针,指向自己(头结点) 3
    if(!rt)
        thrt->LChild=thrt;//若二叉树为空,建立左回指针(也指向头结点)
    else
    {
        thrt->LChild=rt;//rt==boot,也就是二叉树的根 
        pre=thrt;//pre指向头结点 
        InThread(rt);//为二叉树加线索 
        pre->RChild=thrt;//同上1
        pre->Rtag=1;//同上2
        thrt->RChild=pre;//同上3
    }
    return thrt;
}

//中序找前驱 
void InPre(Trees boot)
{
    Trees q=NULL;
    if(boot->Ltag==1)
        pre=boot->LChild;
    else
    {
        for(q=boot->LChild;q->Rtag==0;q=q->RChild)
            pre=q;    
    }    
    if(pre)
        printf("中序找到的前驱为:%d\n",pre->data);    
    else
        printf("无前驱.\n");
}

//中序找后继 
void InNext(Trees boot)
{
    Trees q=NULL;
    if(boot->Rtag==1)
        pre=boot->RChild;
    else
    {
        for(q=boot->RChild;q->Ltag==0;q=q->LChild)
            pre=q;
    }
    if(pre)
        printf("中序找到的后继为:%d\n",pre->data);
    else
        printf("中序遍历无后继.\n");
}

//中序遍历序线索树上的第一个结点 
Trees InFirst(Trees boot)
{
    Trees p=boot;
    if(!p)
        return NULL;
    while(p->Ltag==0)
        p=p->LChild;
    return p;
}

//中序遍历线索二叉树 
void TInOrder(Trees &thrt)
{
    Trees p;
    p=thrt->LChild;
    while(p!=thrt)
    {
        while(p->Ltag==0)
            p=p->LChild;
        printf("%d ",p->data);
        while(p->Rtag==1&&p->RChild!=thrt)
        {
            p=p->RChild;
            printf("%d ",p->data);        
        }
        p=p->RChild;
    }
    printf("\n");
}

int main()
{
    Trees boot=NULL;
    printf("创建二叉树,输入零结束:\n");
    CreateTree(boot);
    
    Trees thrt;//头结点 
    thrt=InOrderThread(boot);
    TInOrder(thrt);//中序遍历线索二叉树 
    
    InPre(boot);//中序找前驱 
    
    InNext(boot);//中序找后继 
    
    Trees bt=InFirst(boot);//中序遍历序线索树上的第一个结点
    printf("中序遍历序线索树上的第一个结点为:%d\n",bt->data);
    
    return 0;
}

 结果:

  

posted on 2018-09-21 21:46  tianzeng  阅读(1201)  评论(0编辑  收藏  举报

导航