樹(shù)

樹(shù)(Tree)
定義

    樹(shù)(Tree) 是n個(gè)(n≥0)個(gè)結(jié)點(diǎn)的有限集。n=0時(shí)稱(chēng)為空樹(shù)。
    在任何一個(gè)非空樹(shù)中:
        (1) 有且僅有一個(gè)特定的稱(chēng)為根(root)的結(jié)點(diǎn);
        (2) 當(dāng)n>1時(shí),其余結(jié)點(diǎn)可分為m個(gè)互不相交的有限集。(子樹(shù)) 

結(jié)點(diǎn)分類(lèi)

    結(jié)點(diǎn)擁有的子樹(shù)數(shù)稱(chēng)為結(jié)點(diǎn)的度(Degree); 
    度為0的結(jié)點(diǎn)稱(chēng)為葉結(jié)點(diǎn)(Leaf) 或終端結(jié)點(diǎn);
    度不為0的結(jié)點(diǎn)稱(chēng)為非終端結(jié)點(diǎn)或分支結(jié)點(diǎn);
    除根結(jié)點(diǎn)之外,分支結(jié)點(diǎn)也稱(chēng)為內(nèi)部結(jié)點(diǎn);
    樹(shù)的度是樹(shù)內(nèi)各結(jié)點(diǎn)的度的最大值。 

抽象數(shù)據(jù)類(lèi)型

ADT 樹(shù)(tree) 
Data 
    樹(shù)是由一個(gè)根結(jié)點(diǎn)和若干棵子樹(shù)構(gòu)成。數(shù)中結(jié)點(diǎn)具有相同的數(shù)據(jù)類(lèi)型和層次關(guān)系 
Operation
    InitTree(*T):
    DestroyTree(*T):
    CreatTree(*T,definition):
    ClearTree(*T):
    TreeEmpty(T):
    TreeDepth(T): 
    Root(T):
    Value(T,cur_e):
    Assign(T,cur_e,value):
    parent(T,cur_e):
    LeftChild(T,cur_e):
    RightSibling(T,cur_e):
    InsertChild(*T,*p,i,c):
    DeleteChild(*T,*p,i):
endADT

樹(shù)的存儲(chǔ)結(jié)構(gòu)

雙親表示法:在每個(gè)結(jié)點(diǎn)中,附設(shè)一個(gè)指示器指示其雙親結(jié)點(diǎn)在數(shù)組中的位置

//  樹(shù)的雙親表示法結(jié)點(diǎn)結(jié)構(gòu)定義
#define MAX_TREE_SIZE 100

typedef char TElemType;             /*樹(shù)結(jié)點(diǎn)的數(shù)據(jù)類(lèi)型*/ 
typedef struct PTNode{              /*結(jié)點(diǎn)結(jié)構(gòu)*/ 
    TElemType data;                 /*結(jié)點(diǎn)數(shù)據(jù)*/ 
    int parent;                     /*雙親位置*/ 
}PTNode;

typedef struct{                     /*樹(shù)結(jié)構(gòu)*/ 
    PTNode nodes[MAX_TREE_SIZE];    /*結(jié)點(diǎn)數(shù)組*/ 
    int r,n;                        /*根的位置和結(jié)點(diǎn)數(shù)*/ 
}PTree;

每個(gè)結(jié)點(diǎn)有多個(gè)指針域,其中每個(gè)指針指向一棵子樹(shù)的根結(jié)點(diǎn)。(多重鏈表表示法)造成浪費(fèi)

孩子表示法:把每個(gè)結(jié)點(diǎn)的孩子結(jié)點(diǎn)排列起來(lái),以單鏈表作存儲(chǔ)結(jié)構(gòu)。則n個(gè)孩子有n個(gè)孩子鏈表。
如果是葉子結(jié)點(diǎn)則此單鏈表為空,然后n個(gè)頭指針又組成一個(gè)線(xiàn)性表,采用順序存儲(chǔ)結(jié)構(gòu),存放進(jìn)一個(gè)一維數(shù)組。

//  樹(shù)的孩子表示法結(jié)構(gòu)定義
#define MAX_TREE_SIZE 100
typedef struct CTNode{      /* 孩子結(jié)點(diǎn) */ 
    int child;
    struct CTNode *next;
}*ChilePtr; 
typedef struct{             /* 表頭結(jié)構(gòu) */ 
    TElemType data;
    ChildPtr firstchild;
}CTBox;
typedef struct{             /* 樹(shù)結(jié)構(gòu) */ 
    CTBox nodes[MAX_TREE_SIZE];
    int r,n;                /* 根的位置和結(jié)點(diǎn)數(shù) */ 
}Ctree;

孩子兄弟表示法:任意一棵樹(shù),它的結(jié)點(diǎn)的第一個(gè)孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。
因此,設(shè)置兩個(gè)指針,分別指向該結(jié)點(diǎn)的第一個(gè)孩子和此結(jié)點(diǎn)的右兄弟。

//  樹(shù)的孩子表示法結(jié)構(gòu)定義 
typedef struct CSNode {
    TElemType data;
    struct CSNode *firstchild,*rightsib;
}CSNode,*CSTree;

二叉樹(shù)(Binary Tree)
是n個(gè)結(jié)點(diǎn)的有限集合,該集合或者為空集,或者由一個(gè)根結(jié)點(diǎn)和兩棵互不相交的,分別稱(chēng)為根結(jié)點(diǎn)的左子樹(shù)和右子樹(shù)的二叉樹(shù)組成。

特點(diǎn):

滿(mǎn)二叉樹(shù):   
    在一棵二叉樹(shù)中,如果所有分支結(jié)點(diǎn)都存在左子樹(shù)和右子樹(shù),并且所有葉子都在同一層上,這樣的樹(shù)叫~;
完全二叉樹(shù):
    對(duì)一棵具有n個(gè)結(jié)點(diǎn)的二叉樹(shù)按層序編號(hào),如果編號(hào)為i的結(jié)點(diǎn)與同樣深度的滿(mǎn)二叉樹(shù)中編號(hào)為i的結(jié)點(diǎn)在二叉樹(shù)中的位置完全相同,則這棵二叉樹(shù)稱(chēng)為完全二叉樹(shù)。

滿(mǎn)二叉樹(shù)一定是一棵完全二叉樹(shù),但是完全二叉樹(shù)不一定是滿(mǎn)的。

滿(mǎn)二叉樹(shù)特點(diǎn):
    葉子只能出現(xiàn)在最下一層;
    非葉子結(jié)點(diǎn)的度一定是2;
    在同樣深度的二叉樹(shù)中,滿(mǎn)二叉樹(shù)的結(jié)點(diǎn)個(gè)數(shù)最多,葉子數(shù)最多。 
完全二叉樹(shù)特點(diǎn):
    葉子結(jié)點(diǎn)只能出現(xiàn)在最下兩層;
    最下層的葉子一定集中在左部連續(xù)位置;
    倒數(shù)二層,若有葉子結(jié)點(diǎn),一定都在右部連續(xù)部分;
    如果結(jié)點(diǎn)度為1,則該結(jié)點(diǎn)只有左孩子,集不存在只有右子樹(shù)的情況;
    同樣結(jié)點(diǎn)數(shù)的二叉樹(shù),完全二叉樹(shù)的深度最小。 

性質(zhì):

    性質(zhì)1:在二叉樹(shù)的第i層上至多有2^(i-1)個(gè)結(jié)點(diǎn);
    性質(zhì)2:深度為k的二叉樹(shù)至多有2^k-1個(gè)結(jié)點(diǎn);
    性質(zhì)3:對(duì)任何一棵二叉樹(shù)T,如果其終端結(jié)點(diǎn)數(shù)為n0,度為2的結(jié)點(diǎn)數(shù)為n2,則n0=n2+1; 
    性質(zhì)4:具有n個(gè)結(jié)點(diǎn)的完全二叉樹(shù)的深度為|log2 n|+1;(|x|為不大于x的最大整數(shù))
    性質(zhì)5:如果對(duì)一棵有n個(gè)結(jié)點(diǎn)的完全二叉樹(shù),對(duì)任一結(jié)點(diǎn)i:
            1)如果i=1,則結(jié)點(diǎn)i是二叉樹(shù)的根;如果i>1,則其雙親是結(jié)點(diǎn);
            2)如果2i>n,則結(jié)點(diǎn)i無(wú)左孩子,否則其左孩子是結(jié)點(diǎn)2i; 
            3)如果2i+1>n,則結(jié)點(diǎn)i無(wú)右孩子,否則其右孩子是結(jié)點(diǎn)2i+1。

二叉樹(shù)的存儲(chǔ)結(jié)構(gòu)

順序存儲(chǔ)結(jié)構(gòu):完全二叉樹(shù)
鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu):

/* 二叉樹(shù)的二叉鏈表結(jié)點(diǎn)結(jié)構(gòu)定義*/ 
/* lchild data rchild */ 
typedef struct BiTNode{             /* 結(jié)點(diǎn)結(jié)構(gòu) */
    TElemType data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

遍歷二叉樹(shù):
二叉樹(shù)的遍歷(traversing binary tree)
指從根結(jié)點(diǎn)出發(fā),按照某種次序依次訪(fǎng)問(wèn)二叉樹(shù)中所有結(jié)點(diǎn),使得每個(gè)結(jié)點(diǎn)被且僅被訪(fǎng)問(wèn)一次 ;

前序遍歷:
若二叉樹(shù)為空,則返回;否則先訪(fǎng)問(wèn)根結(jié)點(diǎn),然后前序遍歷左子樹(shù),再前序遍歷右子樹(shù);

/* 二叉樹(shù)的前序遍歷遞歸算法 */ 
void PreOrderTraverse(BiTree T){
    if(T == NULL)
        return;
    printf("%c",T->data);
    PreOrderTraverse(T->lchild);
    preOrderTraverse(T->rchild);
}

中序遍歷:
若二叉樹(shù)為空,則返回;否則從根結(jié)點(diǎn)開(kāi)始(注意不是先訪(fǎng)問(wèn)根結(jié)點(diǎn)) ,中序遍歷根結(jié)點(diǎn)的左子樹(shù),然后訪(fǎng)問(wèn)根結(jié)點(diǎn),最后中序遍歷右子樹(shù);

/* 二叉樹(shù)的中序遍歷遞歸算法 */ 
void InOrderTraverse(BiTree T){
    if(T == NULL)
        return;
    InOrderTraverse(T->lchild);
    printf("%c",T->data);
    InOrderTraverse(T->rchild);
}

后序遍歷:
若二叉樹(shù)為空,則返回;否則從左到右先葉子后結(jié)點(diǎn)的方式遍歷訪(fǎng)問(wèn)左右子樹(shù),最后訪(fǎng)問(wèn)根結(jié)點(diǎn);

/* 二叉樹(shù)的中序遍歷遞歸算法 */ 
void PostOrderTraverse(BiTree T){
    if(T == NULL)
        return;
    PostOrderTraverse(T->lchild);
    PostOrderTraverse(T->rchild);
    printf("%c",T->data);
}

層序遍歷:
若二叉樹(shù)為空,則返回;否則從樹(shù)的第一層,也就是根結(jié)點(diǎn)開(kāi)始訪(fǎng)問(wèn),從上而下逐層遍歷,在同一層中,按從左到右的順序?qū)Y(jié)點(diǎn)逐個(gè)訪(fǎng)問(wèn);

建立二叉樹(shù):

/* 默認(rèn)用戶(hù)按前序遍歷序列輸入二叉樹(shù)數(shù)據(jù)  */ 
/* #表示空樹(shù),構(gòu)建二叉鏈表來(lái)表示二叉樹(shù)T */
void CreatBiTree(BiTree *T) {
    TElemType ch;
    scanf("%c",&ch);
    if(ch=='#')
        *T=NULL;
    else{
        *T=(BiTree)malloc(sizeof(BiTNode));
        if(!*T)
            exit(0);
        (*T)->data = ch;
        CreatBiTree(&(*T)->lchild);
        CreatBiTree(&(*T)->rchild);
    }       
}

線(xiàn)索二叉樹(shù)(Threaded Binary Tree)
指向前驅(qū)和后繼的指針?lè)Q為線(xiàn)索,加上線(xiàn)索的二叉鏈表稱(chēng)為線(xiàn)索鏈表,相應(yīng)的二叉樹(shù)就稱(chēng)為線(xiàn)索二叉樹(shù)。
lchild ltag data rtag rchild
ltag為0時(shí),指向該結(jié)點(diǎn)的左孩子,為1時(shí)指向該結(jié)點(diǎn)的前驅(qū);
rtag為0時(shí),指向該結(jié)點(diǎn)的右孩子,為1時(shí)指向該結(jié)點(diǎn)的后繼;

線(xiàn)索二叉樹(shù)的結(jié)構(gòu)實(shí)現(xiàn):

/* 二叉樹(shù)的二叉線(xiàn)索存儲(chǔ)結(jié)構(gòu)定義 */
typedef enum{Link,Thread} PointerTag;   /*Link == 0 表示指向左右孩子指針 */
                                        /*Thread == 0 表示指向前驅(qū)或后繼的線(xiàn)索 */ 
typedef struct BiThrNode{               /*二叉樹(shù)線(xiàn)索存儲(chǔ)結(jié)點(diǎn)結(jié)構(gòu) */
    TElemtype data;     
    struct BiThrNode *lchild,*rchild;
    PointerTag LTag;
    PointerTag RTag; 
}BiThrNode,*BiThrTree;
/*中序遍歷進(jìn)行中序線(xiàn)索化 */
BiThrTree pre;
void InThreading(BiThrTree p){
    if(p){
        InThreading(p->lchild);     /*遞歸左子樹(shù)線(xiàn)索化 */
        
        if(!p->lchild){             /*沒(méi)有左孩子 */
            p->LTag=Thread;         /*前驅(qū)線(xiàn)索*/
            p->lchild=pre;          /*左孩子指針指向前驅(qū) */
        }
        
        if(!pre->rchild){           /*前驅(qū)沒(méi)有右孩子 */
            pre->RTag=Thread;       /*后繼線(xiàn)索 */
            pre->rchild=p;          /*前驅(qū)右孩子指針指向后繼(當(dāng)前結(jié)點(diǎn)p) */
        }
        
        pre=p;                      /*保持pre指向p的前驅(qū) */
        
        InThreading(p->rchild);     /*遞歸右子樹(shù)線(xiàn)索化 */
    }
}
/*中序遍歷二叉線(xiàn)索鏈表表示的二叉樹(shù) */
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;
}

實(shí)例:創(chuàng)建一棵線(xiàn)索二叉樹(shù),并中序遍歷該二叉樹(shù)

#include <stdio.h>
#include <stdlib.h>

typedef char ElemType;

//  線(xiàn)索存儲(chǔ)標(biāo)志位
//  Link(0):表示指向左右孩子的指針
//  Thread(1) :表示指向前驅(qū)后繼的線(xiàn)索
typedef enum {Link,Thread} PointerTag;

typedef struct BiThrNode {
    ElemType data;
    struct BiThrNode *lchild,*rchild;
    PointerTag ltag;
    PointerTag rtag;
} BiThrNode,*BiThrTree;

//  創(chuàng)建一棵二叉樹(shù),約定用戶(hù)遵照前序遍歷的方式輸入數(shù)據(jù)
void CreatBiThrTree(BiThrTree *T) {
    char c;
    scanf("%c",&c);
    if(' ' == c)
        *T = NULL;
    else {
        *T = (BiThrNode *)malloc(sizeof(BiThrNode));
        (*T)->data = c;
        (*T)->ltag = Link;
        (*T)->rtag = Link;
        CreatBiThrTree(&(*T)->lchild);
        CreatBiThrTree(&(*T)->rchild);
    }
}

//  中序遍歷線(xiàn)索化(遞歸)
BiThrTree pre;  //全局變量,始終指向剛剛訪(fǎng)問(wèn)過(guò)的結(jié)點(diǎn)

void InThreading(BiThrTree T) {
    if(T) {
        InThreading(T->lchild);

        if(!T->lchild) {
            T->ltag = Thread;
            T->lchild = pre;
        }

        if(!pre->rchild) {
            pre->rtag = Thread;
            pre->rchild = T;
        }

        pre = T;

        InThreading(T->rchild);
    }
}

void InOrderThreading(BiThrTree *p,BiThrTree T) {
    *p = (BiThrNode *)malloc(sizeof(BiThrNode));
    (*p)->ltag = Link;
    (*p)->rtag = Thread;
    (*p)->rchild = *p;
    if(!T){
        (*p)->lchild = *p;
    }
    else{
        (*p)->lchild = T;
        pre = *p; 
        InThreading(T);
        pre->rchild = *p;
        pre->rtag = Thread;
        (*p)->rchild = pre; 
    }
}
//  中序遍歷二叉樹(shù),非遞歸 
void InOrederTraverse(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;
    }
}

int main(int argc, char *argv[]) {
    BiThrTree p,T = NULL;
    CreatBiThrTree(&T);
    InOrderThreading(&p,T);
    printf("中序遍歷輸出結(jié)果為:");
    InOrederTraverse( p ) ;
    printf("\n");

    return 0;
}

實(shí)例:創(chuàng)建一棵二叉樹(shù),并分別按前序、中序、后序方式遍歷二叉樹(shù)。

#include <stdio.h>
#include <stdlib.h>

typedef char ElemType;
typedef struct BiTNode {
    char data;
    struct BiTNode *lchild,*rchild;
} BiTNode,*BiTree;

//  創(chuàng)建一棵二叉樹(shù) ,約定用戶(hù)遵照前序遍歷的方式輸入數(shù)據(jù)
CreateBiTree(BiTree *T) {
    char c;
    scanf("%c",&c);
    if(' '==c) {
        *T = NULL;
    } else {
        *T = (BiTNode *)malloc(sizeof(BiTNode));
        (*T)->data = c;
        CreateBiTree(&(*T)->lchild);
        CreateBiTree(&(*T)->rchild);
    }
}

//  前序遍歷二叉樹(shù)
PreOrderTraverse(BiTree T) {
    if( T ) {
        printf("%c",T->data);
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
}

//  中序遍歷二叉樹(shù)
InOrderTraverse(BiTree T) {
    if( T ) {
        InOrderTraverse(T->lchild);
        printf("%c",T->data);
        InOrderTraverse(T->rchild);
    }
}
//  后序遍歷二叉樹(shù)
PostOrderTraverse(BiTree T) {
    if( T ) {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        printf("%c",T->data);
    }
}

int main(int argc, char *argv[]) {

    printf("建一棵二叉樹(shù) ,約定用戶(hù)遵照前序遍歷的方式輸入數(shù)據(jù)\n");
    BiTree T = NULL;

    CreateBiTree(&T) ;
    printf("\n 前序遍歷結(jié)果是:\n");
    PreOrderTraverse(T);
    printf("\n 中序遍歷結(jié)果是:\n");
    InOrderTraverse(T);
    printf("\n 后序遍歷結(jié)果是:\n");
    PostOrderTraverse(T);
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容