线索二叉树

内容纲要

对于具有 n 个结点的二叉树,采用二叉链存储结构时,每个结构有两个指针域,总共有 2n 个指针域,又由于只有 n−1 个结点被有效指针域所指向,则共有 2n−(n−1)=n+1 个空指针域。 遍历二叉树的结果是一个结点的线性序列,可以利用这些空链域存放指向结点的前驱结点和后继结点的地址。其规定是当某个结点的左指针为空时,令该指针指向这个线性序列中该结点的前驱结点;当某结点的右指针为空时,令该指针指向这个线性序列中该结点的后继结点,这样指向该线性序列中的“前驱结点”和“后继结点”称为线索。 创建线索的过程称为线索化。线索化的二叉树称为线索二叉树。由于遍历方式不同,产生的遍历线性序列也不同,会得到相应的线索二叉树。一般有先序线索二叉树、中序线索二叉树和后序线索二叉树。创建线索二叉树的目的就是提高该遍历过程的效率。 那么,在线索二叉树中如何区分指向的是左孩子结点还是前驱结点,右指针指向的是右孩子还是右孩子结点呢?为此,在结点的存储结构上增加两个标志位来区分这两种情况: 预览大图预览大图

#include <stdio.h>
#include <stdlib.h>
#define MaxSize 50
typedef char ElemType;
typedef struct node {
    ElemType data;          //结点数据域
    int ltag, rtag;         //增加的线索标记
    struct node *lchild;    //左孩子或线索指针
    struct node *rchild;    //右孩子或线索指针
} TBTNode;
void CreateTBTNode(TBTNode *&b, char *str);
void DispTBTNode(TBTNode *b);
void Thread(TBTNode *&p);
TBTNode *CreateThread(TBTNode *b);
void ThInOrder(TBTNode *tb);
TBTNode *pre;                   //全局变量
//对二叉排序树进行线索化
void Thread(TBTNode *&p) {
    if(p != NULL) {
        Thread(p->lchild);      //左孩子线索化

        if(p->lchild == NULL) { //左孩子不存在,进行前驱结点线索化
            p->lchild = pre;    //建立当前结点的前驱结点线索
            p->ltag = 1;
        } else {
            p->ltag = 0;        //p结点的左子树已线索化
        }

        if(pre->rchild == NULL) { //对pre的后继结点线索化
            pre->rchild = p;    //建立前驱结点的后继结点线索
            pre->rtag = 1;
        } else {
            pre->rtag = 0;
        }

        pre = p;
        Thread(p->rchild);      //右子树线索化
    }
}
//中序线索化二叉树
TBTNode *CreateThread(TBTNode *b) {
    TBTNode *root;
    root = (TBTNode *)malloc(sizeof(TBTNode));  //创建根节点
    root->ltag = 0;
    root->rtag = 1;
    root->lchild = b;

    if(b == NULL)               //空二叉树
        root->lchild = root;
    else {
        root->lchild = b;
        pre = root;              //pre是*b的前驱节点,供加线索用
        Thread(b);                //中序遍历线索化二叉树
        pre->rchild = root;      //最后一个节点的后继处理,加入指向根节点的线索
        pre->rtag = 1;
        root->rchild = pre;      //根节点右线索化
    }

    /*
    在某种遍历方式的线索二叉树中,若开始结点 p 没有左孩子,将 p 结点的左指针改为线索,对其指针仍为空;
    若最后结点 q 没有右孩子,将 q 结点的右指针改为线索,其右指针仍为空。
    对于其他结点 r ,若它没哟右左孩子,将左指针改为指向前驱结点的非空线索;
    若它没有右孩子,将右指针改为后继结点的非空线索。
    为了使创建二叉树的算法设计方便,为线索二叉树中再增加一个头结点。
    头结点的 data 域为空;lchild 指向无线索时的根结点,ltag 为 0 ;
    rtag 指向按某种方式遍历二叉树时的最后一个结点,rtag 为 1 。
    */
    return root;
}
//遍历线索化二叉树
void ThInOrder(TBTNode *tb) {
    TBTNode *p = tb->lchild;                    //p指向根结点

    while(p != tb) {
        while(p->ltag == 0)p = p->lchild;       //找开始结点

        printf(%c, p->data);                  //访问开始结点

        while(p->rtag == 1 && p->rchild != tb) {
            p = p->rchild;
            printf(%c, p->data);
        }

        p = p->rchild;
    }
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注