线索二叉树(C语言描述)

  线索二叉树的定义:还是按照链二叉树的方法创建,只不过在结点原本为空的左指针改为指向该结点在中序遍历中的前驱,结点原本为空的右指针改为指向该结点在中序遍历中的后继,也就是说把空的指针给利用了起来。

1.定义结构体

与链二叉树不同的是结点增加了两个数据,判断指针下一个连接的是树还是线索

typedef enum{Link,Thread}PointerTag;  //0表示连接 ,1表示线索
typedef struct BiTNode{
    char data;
    struct BiTNode *lchild,*rchild;  //左右孩子树
    PointerTag ltag;  //Link代表连接,Thread代表线索 
    PointerTag rtag;
}BiTNode,*BiTree;
BiTree pre; //全局变量 ,始终指向访问过的节点 

2.二叉树的创建

//二叉树的建立
void createBiTree(BiTree *T)
{
    char c;
    scanf("%c",&c);
    
    if(c=='$')
    {
        *T=NULL;
    }
    else
    {
        *T=(BiTree)malloc(sizeof(BiTNode));
        (*T)->data=c;
        (*T)->ltag=Link;   //先设定都有左子树 
        (*T)->rtag=Link;   //先设定都有右子树
        createBiTree(&(*T)->lchild);   //按照先序遍历创建二叉树 
        createBiTree(&(*T)->rchild);
    }
}

3.将二叉树中的空指针线索化,pre指向最后一个结点

就只是将二叉树中空的指针线索化,一开始的pre指向的是头结点

void createThread(BiTree T)
{
    if(T) //线索二叉树不为空 
    {
        createThread(T->lchild);
        
        if(!T->lchild)  //如果该节点没有左子树 
        {
            T->ltag=Thread;  //将该结点左边线索化 
            T->lchild=pre;   //该结点的前驱指向上一个结点 
        }
        
        if(!pre->rchild) //如果上一个结点没有右子树
        {
            pre->rtag=Thread;  //将该结点右边线索化 
            pre->rchild=T;       //将上一个结点的后继指向该结点 
        }
        
        pre=T;//向下循环 
        
        createThread(T->rchild);    
    }
}

4.添加头结点

步骤如下:

(1).先创建一个头结点,

(2).头结点的左指针指向该二叉树的根节点,表示为Link. 

(3)中序遍历的第一个结点的左指针表示为Thread,指向头结点 

(4)中序遍历的尾结点的的右指针表示为Thrad,指向头结点

(5).头结点的右指针指向的是二叉树中序遍历的尾结点,表示为Thread.

//线索二叉树增加头结点
void createHeadNode(BiTree *thrt,BiTree T)
{
    *thrt=(BiTree)malloc(sizeof(BiTNode));  //创建头结点
    if(!thrt)
    {
        printf("创建空间失败\n");
    }
    
    (*thrt)->ltag=Link;     //左边是连接 
    (*thrt)->rtag=Thread;   //右边是线索
    (*thrt)->rchild=*thrt;  //右边指针指向自己
    if(!T) //如果二叉树为空 
    {
        (*thrt)->lchild=*thrt;
    } 
    else  //如果二叉树不为空 
    {
        (*thrt)->lchild=T;  //头结点的左边指针指向根节点 
        pre=*thrt;         //将前驱的值指向头结点 
        createThread(T);    //中序遍历进行中序线索化,pre指向中序遍历的最后一个结点
        pre->rtag=Thread;    //最后一个结点的右标志为线索
        pre->rchild=*thrt;  //最后一个结点的右指针指向头结点
        (*thrt)->rchild=pre;  //头结点的右指针指向最后一个节点 
    }
} 

5.按照中序遍历的方法非递归进行遍历

中序遍历:先找到最左节点,再访问其根节点,再访问右结点

这里的方法是:

1.先找到最左节点,然后打印该结点

2.如果该结点存在右子树,访问右子树,则返回循环

2.如果不存在右子树,则访问线索,打印出该结点,访问其右子树,然后循环

void middleSort(BiTree T)
{
    BiTree p;
    p=T->lchild;//p是该二叉树的根节点
    
    while(p!=T)  //空树或遍历结束时,p==T 
    {
        while(p->ltag==Link)  //先找到最左结点 
        {
            p=p->lchild;
        }
        printf("%c  ",p->data);
        
        while(p->rtag==Thread&&p->rchild!=T)
        {
            p=p->rchild;
            printf("%c  ",p->data);
        }
        p=p->rchild;  //若p->rchild不是线索(是右孩子),p指向右孩子,返回循环
    }
}

所有的代码如下:

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

typedef enum{Link,Thread}PointerTag;  //0表示连接 ,1表示线索
typedef struct BiTNode{
    char data;
    struct BiTNode *lchild,*rchild;  //左右孩子树
    PointerTag ltag;  //Link代表连接,Thread代表线索 
    PointerTag rtag;
}BiTNode,*BiTree;
BiTree pre; //全局变量 ,始终指向访问过的节点 

//二叉树的建立
void createBiTree(BiTree *T)
{
    char c;
    scanf("%c",&c);
    
    if(c=='$')
    {
        *T=NULL;
    }
    else
    {
        *T=(BiTree)malloc(sizeof(BiTNode));
        (*T)->data=c;
        (*T)->ltag=Link;   //先设定都有左子树 
        (*T)->rtag=Link;   //先设定都有右子树
        createBiTree(&(*T)->lchild);   //按照先序遍历创建二叉树 
        createBiTree(&(*T)->rchild);
    }
}

//二叉树的中序遍历来线索化  ,线索化结束后pre指向最后的一个结点 
void createThread(BiTree T)
{
    if(T) //线索二叉树不为空 
    {
        createThread(T->lchild);
        
        if(!T->lchild)  //如果该节点没有左子树 
        {
            T->ltag=Thread;  //将该结点左边线索化 
            T->lchild=pre;   //该结点的前驱指向上一个结点 
        }
        
        if(!pre->rchild) //如果上一个结点没有右子树
        {
            pre->rtag=Thread;  //将该结点右边线索化 
            pre->rchild=T;       //将上一个结点的后继指向该结点 
        }
        
        pre=T;//向下循环 
        
        createThread(T->rchild);    
    }
}

//线索二叉树增加头结点
void createHeadNode(BiTree *thrt,BiTree T)
{
    *thrt=(BiTree)malloc(sizeof(BiTNode));  //创建头结点
    if(!thrt)
    {
        printf("创建空间失败\n");
    }
    
    (*thrt)->ltag=Link;     //左边是连接 
    (*thrt)->rtag=Thread;   //右边是线索
    (*thrt)->rchild=*thrt;  //右边指针指向自己
    if(!T) //如果二叉树为空 
    {
        (*thrt)->lchild=*thrt;
    } 
    else  //如果二叉树不为空 
    {
        (*thrt)->lchild=T;  //头结点的左边指针指向根节点 
        pre=*thrt;         //将前驱的值指向头结点 
        createThread(T);    //中序遍历进行中序线索化,pre指向中序遍历的最后一个结点
        pre->rtag=Thread;    //最后一个结点的右标志为线索
        pre->rchild=*thrt;  //最后一个结点的右指针指向头结点
        (*thrt)->rchild=pre;  //头结点的右指针指向最后一个节点 
    }
} 


//中序遍历线索二叉树T的非递归算法
void middleSort(BiTree T)
{
    BiTree p;
    p=T->lchild;//p是该二叉树的根节点
    
    while(p!=T)  //空树或遍历结束时,p==T 
    {
        while(p->ltag==Link)  //先找到最左结点 
        {
            p=p->lchild;
        }
        printf("%c  ",p->data);
        
        while(p->rtag==Thread&&p->rchild!=T)
        {
            p=p->rchild;
            printf("%c  ",p->data);
        }
        p=p->rchild;  //若p->rchild不是线索(是右孩子),p指向右孩子,返回循环
    }
}

int main()
{
    printf("请输入二叉树,按照先序遍历的顺序,空指针用$号表示\n");
    BiTree T,K;
    
    createBiTree(&T);      //按照先序遍历的顺序生成一个二叉树
    createHeadNode(&K,T);   //给二叉树添加头结点并且线索化
    middleSort(K);      //按照中序遍历的方法非递归输出值 
}

  这就是完整的线索二叉树了,可能线索二叉树也有其它的表示方式,也可以尝试写一下。

猜你喜欢

转载自www.cnblogs.com/qian-yi/p/12739693.html