数据结构-线索二叉树

前言

以前咱们研究二叉树,今天咱们继续研究二叉树的优化--线索二叉树。markdown

产生背景

在二叉树中,结点的度为0~2的范围。当度为0或1时,结点中为指向孩子的空间是没有用的,如图: 学习

图中结点F、G、H、I、J的度为0,也就是没有左右孩子。结点E的度为1,没有右孩子。会有必定的空间浪费。线索二叉树就是利用这些浪费的空间,进而提升了对二叉树操做时的效率。

利用空间

浪费的空间利用起来,把没用的左右孩子的区域用来指向前驱或者后继结点。这样树在使用起来的时候,减小遍历的次数,这样会更有效率。如图: 优化

图中使用的中序遍历的方式,中序遍历结果为:HDIBJEAFCG

结点增长标志位

经过上面的图片,很容易理解线索二叉树的相关逻辑。可是咱们会遇到一个问题:如何区分孩子区域指向的是孩子结点仍是前驱或后继结点呢? spa

例如:图中咱们知道结点E的左孩子是J,而J结点的右孩子区域用于指向后继E结点。

经过对结点增长标志位来区分是孩子结点仍是前驱后继结点。 指针

结点中0表明的是孩子结点,1代买是前驱后继结点。左边和右边分别表明左孩子区域标示和右孩子区域标示。

似曾相识-双向链表

线索化的二叉树,其实和咱们以前学习过的双向链表很相似;因此咱们能够给二叉树增长一个头结点,这样在遍历的时更便捷: code

代码

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

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100

typedef int Status;
typedef char CElemType;
CElemType Nil = '#';

int indexs = 1;
typedef char String[24];

String str;
Status strAssign(String T, char *chars) {
    if (strlen(chars) > MAXSIZE) {
        return ERROR;
    } else {
        T[0]=strlen(chars);//下标0的位置存储字符串长度
        for (int 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, rTag;
}BiThrNode, *BiThrTree;

/** 打印 */
Status visit(CElemType e) {
    printf("%c ", e);
    return OK;
}

/** 构造二叉树 */
Status createBiThrTree(BiThrTree *T) {
    CElemType 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);
        if ((*T)->lchild) {//左孩子存在,标记为孩子指针
            (*T)->lTag = Link;
        }
        
        createBiThrTree(&(*T)->rchild);
        if ((*T)->rchild) {//右孩子存在,标记为孩子指针
            (*T)->rTag = Link;
        }
    }
    
    return OK;
}

BiThrTree pre;//全局变量,指向前一个结点
void inThreading(BiThrTree p) {
    if (p) {
        //递归左子树
        inThreading(p->lchild);
        if (!p->lchild) {//左孩子不存在,设置作孩子前驱线索
            p->lTag = Thread;
            p->lchild = pre;
        } else {
            p->lTag = Link;
        }
        
        if (!pre->rchild) {//前驱先说右孩子不存在,设置前驱结点的右孩子线索为当前结点
            pre->rTag = Thread;
            pre->rchild = p;
        } else {
            pre->rTag = Link;
        }
        
        pre = p;
        //递归右子树
        inThreading(p->rchild);
    }
}

/** 中序遍历二叉树T,并线索化,建立头结点 */
Status inOrderThreading(BiThrTree T, BiThrTree *Thrt) {
    //头结点
    *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);
        
        //最后一个结点线索化
        pre->rchild = *Thrt;
        pre->rTag = Thread;
        (*Thrt)->rchild = pre;
    }
    
    return OK;
}

/** 中序遍历二叉线索树 */
Status inOrderTraverse(BiThrTree T) {
    BiThrTree p;
    p=T->lchild;//p指向根结点
    while (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[]) {
    // insert code here...
    printf("Hello, 线索二叉树!\n");
    
    BiThrTree H,T;
    
    strAssign(str,"ABDH##I##EJ###CF##G##");
    
    createBiThrTree(&T); /* 按前序产生二叉树 */
    inOrderThreading(T,&H); /* 中序遍历,并中序线索化二叉树 */
    inOrderTraverse(H);
    printf("\n");
    
    return 0;
}
复制代码

相关文章
相关标签/搜索