數據結構-線索二叉樹

前言

以前咱們研究二叉樹,今天咱們繼續研究二叉樹的優化--線索二叉樹。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;
}
複製代碼

相關文章
相關標籤/搜索