数据结构与算法11——线索二叉树

2020-04-29  本文已影响0人  Foxhoundsun

概念

链式存储二叉树的时,每个节点都有一个左子树节点指针和一个右子树指针。
当某个结点没有左子树和右子树的节点时,把这个节点的左子树指针指向遍历的前一个节点,同理该节点无右子树的时候,右子树节点指向遍历的下一个节点

虽然可以在每个节点中增加两个指针域来存放遍历时得到的前驱和后继信息,但是这样会造成结构的存储密度大大降低。由于有n个结点的二叉链表中必定存在n+1个空链域,因此充分利用这些空链域来存放节点的前驱和后继信息。

image.png
typedef char CElemType;
// Link==0表示指向左右孩子指针,
// Thread==1表示指向前驱或后继的线索
typedef enum {Link,Thread} PointerTag;
// 线索二叉树存储结点结构
typedef struct BiThrNode{
    //数据
    CElemType data;
    //左右孩子指针
    struct BiThrNode *lchild,*rchild;
    //左右标记
    PointerTag LTag;
    PointerTag RTag;
}BiThrNode,*BiThrTree;

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

结构

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */

// Status是函数的类型,其值是函数结果状态代码,如OK等
typedef int Status;
typedef char CElemType;
// 字符型以空格符为空
CElemType Nil='#';
#pragma mark--二叉树构造
int indexs = 1;
typedef char String[24]; /*  0号单元存放串的长度 */
String str;
Status StrAssign(String T,char *chars)
{
    int i;
    if(strlen(chars)>MAXSIZE)
        return ERROR;
    }else{
        T[0]=strlen(chars);
        for(i=1;i<=T[0];i++)
            T[i]=*(chars+i-1);
        return OK;
    }
}

构造二叉树
按照前序输入结点的值,构造线索二叉树

Status CreateBiThrTree(BiThrTree *T){
    CElemType h;
    //scanf("%c",&h);
    //获取字符
    h = str[indexs++];
    if (h == Nil) {
        *T = NULL;
    }else{
        *T = (BiThrTree)malloc(sizeof(BiThrNode));
        if (!*T) {
            exit(OVERFLOW);
        }
        //生成根结点(前序)
        (*T)->data = h;
        //递归构造左子树
        CreateBiThrTree(&(*T)->lchild);
        //存在左孩子->将标记LTag设置为Link
        if ((*T)->lchild) (*T)->LTag = Link;
        //递归构造右子树
        CreateBiThrTree(&(*T)->rchild);
        //存在右孩子->将标记RTag设置为Link
        if ((*T)->rchild) (*T)->RTag = Link;
    }
    return OK;
}

操作
** 中序线索化 **

//中序遍历进行中序线索化
void InThreading(BiThrTree p){

    // InThreading(p->lchild);
    if (p) {
        //递归左子树线索化
        InThreading(p->lchild);
        //无左孩子
        if (!p->lchild) {
            //前驱线索
            p->LTag = Thread;
            //左孩子指针指向前驱
            p->lchild  = pre;
        }else
        {
            p->LTag = Link;
        }
        //前驱没有右孩子
        if (!pre->rchild) {
            //后继线索
            pre->RTag = Thread;
            //前驱右孩子指针指向后继(当前结点p)
            pre->rchild = p;
        }else
        {
            pre->RTag = Link;
        }
        //保持pre指向p的前驱
        pre = p;
        //递归右子树线索化
        InThreading(p->rchild);
    }
}

中序遍历二叉树,同时进行中序线索化

Status InOrderThreading(BiThrTree *Thrt , BiThrTree T){
    *Thrt=(BiThrTree)malloc(sizeof(BiThrNode));
    if (! *Thrt) {
        exit(OVERFLOW);
    }
    //建立头结点;
    (*Thrt)->LTag = Link;
    (*Thrt)->RTag = Thread;
    //右指针回指向
    (*Thrt)->rchild = (*Thrt);
    // 若二叉树空,则左指针回指
    if (!T) {
        (*Thrt)->lchild=*Thrt;
    }else{
        (*Thrt)->lchild=T;
        pre=(*Thrt);
        //中序遍历进行中序线索化
        InThreading(T);
        //最后一个结点rchil 孩子
        pre->rchild = *Thrt;
        //最后一个结点线索化
        pre->RTag = Thread;
        (*Thrt)->rchild = pre;
    }
    return OK;
}

中序遍历二叉线索树

Status InOrderTraverse_Thr(BiThrTree T){
    BiThrTree p;
  //p指向根结点
    p=T->lchild; 
    while(p!=T)
    { // 空树或遍历结束时,p==T 
        while(p->LTag==Link)
            p=p->lchild;
        //访问其左子树为空的结点
        if(!visit(p->data)) 
            return ERROR;
        while(p->RTag==Thread&&p->rchild!=T)
        {
            p=p->rchild;
            //访问后继结点 
            visit(p->data);
        }
        p=p->rchild;
    }
    return OK;
}

调用

int main(int argc, const char * argv[]) {
    printf("Hello, 线索化二叉树\n");
    BiThrTree H,T;
    //StrAssign(str,"ABDH#K###E##CFI###G#J##");
    StrAssign(str,"ABDH##I##EJ###CF##G##");
  
  //按前序产生二叉树 
    CreateBiThrTree(&T);
  //中序遍历,并中序线索化二叉树
    InOrderThreading(&H,T);
    InOrderTraverse_Thr(H);
    printf("\n\n");
    return 0;
}

输出

H D I B J E A F C G 
上一篇下一篇

猜你喜欢

热点阅读