二叉树存储(线索化二叉树)

269 阅读2分钟

在使用二叉树链式存储过程中 我们用‘#’占位不存在的结点 如下图所示

image.png

  • 我们可以观察下如果每个空结点都占位符‘#’来代替 那么 占位符为n+1(n为二叉树实际结点) 那么会造成空间浪费 那么我们是否可以利用这些空结点去存储一些我们链的一些信息呢 实际是可以的 这种利用空结点存储链相关信息的方式就叫线索化二叉树

线索化二叉树的构建规则

  1. 结点左子树为空 利用左孩子指向它的前驱结点
  2. 结点的右子树为空 利用右孩子指向它的后继结点
  3. !!!注意:线索化二叉树要统一遵寻某种遍历方式

定义线索化二叉树的结构体

image.png

代码实现

#include <stdio.h>
#include "stdlib.h"
#include "math.h"
#include "time.h"
#include "string.h"

#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){
    T[0] = strlen(chars);
    int i;
    for (i = 1; i <= T[0]; i++) {
        T[i] = *(chars+i-1);
    }
    return OK;
}
//枚举 区别是左右孩子还是线索化
/**
 Link ==0 表示左右孩子
 Thread== 1 表示线索化
 */

typedef enum {Link,Thread}PointerTag;

/**
 线索化 二叉树的结构体
 */
typedef struct BithrNode{
    CElemType data;
    struct BithrNode* lchild,* rchild;
    PointerTag LTag;
    PointerTag RTag;
}BithrNode,*BiThrTree;
//创建一个二叉树

Status CreateBiThrTree(BiThrTree *T){
    CElemType ch = str[indexs++];
    if (ch == Nil) {
        *T = NULL;
    } else {
        *T = (BiThrTree)malloc(**sizeof**(BithrNode));
        (*T)->data = ch;
        CreateBiThrTree(&(*T)->lchild);
        if ((*T)->lchild) {
            (*T)->LTag = Link;
        }      
        CreateBiThrTree(&(*T)->rchild);
        if ((*T)->rchild) {
            (*T)->RTag = Link;
        }
    } 
    return OK;
}
//线索化二叉树
BithrNode * pre; //记录下上个节点
/* 中序遍历进行中序线索化*/
void InThreading(BiThrTree p){
    if (!p) **return**;
    //左子化
    InThreading(p->lchild);
    if (p->lchild == **NULL**) {
        p->lchild = pre;
        p->LTag = Thread;
    } else {
        p->LTag = Link;
    }
    if (pre->rchild == **NULL**) {
        pre->RTag = Thread;
        pre->rchild = p;
    } else {
        pre->RTag = Link;
    }
    pre = p;
    InThreading(p->rchild);    
}

/* 中序遍历二叉树T,并将其中序线索化,Thrt指向头结点 */

Status InOrderThreading(BiThrTree *Thrt , BiThrTree T){
    *Thrt = (BiThrTree)malloc(sizeof(BithrNode));
    (*Thrt)->LTag = Link;
    (*Thrt)->RTag = Thread;   
    (*Thrt)->rchild = *Thrt;
    if (!T) {
        (*Thrt)->lchild = *Thrt;
    } else {
        pre = *Thrt;
        (*Thrt)->lchild = T;
        InThreading(T);
        pre->rchild = *Thrt;
        pre->RTag = Thread;
        (*Thrt)->rchild = pre;
    }
    return OK;
}

  • 在构建线索化二叉树的时候添加了一个头结点 如下图所示

image.png

  • T作为头结点 左子树(作为子树)指向 A 右子树(作为线索化)指向最后一个结点

  • 第一个节点 前驱指向T 做后一个结点后继指向T

  • 那么我们在遍历二叉树的时候可以利用之前构造的线索化信息 不需要递归也能从头到后找到任意一个结点

/*中序遍历二叉线索树T*/

Status InOrderTraverse_Thr(BiThrTree T){
    BiThrTree p;
    p = T->lchild;
    while (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;
    }
    return OK;
}