數據結構——樹

1、樹的基本定義

1、樹的定義:n個結點的有限集合(n>=0)。
2、樹的結點:包含1個數據元素及若干指向其子樹的分支。
3、結點的度:結點所擁有的子樹數量。
4、樹的度:樹中所有結點的度的最大值。
5、結點的層次:從根節點開始爲第一層
6、樹的深度:最大的層次數。

/2、二叉樹(Binary Tree)

1、二叉樹:n個結點的有限集合(n>=0)。特殊在於:n>1時,1個根節點和兩棵互不相交的二叉樹。
2、滿二叉樹:①所有的分支結點都有左子樹和右子樹;②所有的葉子結點都在同一層。
3、完全二叉樹:對有n個結點的二叉樹按照層序編號,若編號i(1<=i<=n)與同樣深度的滿二叉樹的位置完全相同,則該二叉樹爲完全二叉樹。
4、二叉樹的一些性質:

/2.1 二叉樹的順序結構

注意:邏輯結構和物理結構的差異。
邏輯結構:分爲線性和非線性。(樹是非線性結構)
物理結構(存儲結構):分爲順序、鏈式、索引、哈希等,表徵數據是如何存儲的。(因此樹結構也可以有順序或鏈式存儲結構)

二叉樹的順序存儲結構如下:

//二叉樹的順序結構中:一個數組和一個表示位置的結構體。數組存放數據,下標從0開始;位置表徵結點的層數和本層序號數。
typedef TElemType SqBiTree[MAX_TREE_SIZE];  //0號單元存儲根節點,使用一個數組存放數據
typedef struct 
{
    int level, order;   //結點的層,本層序號(按照滿二叉樹計算)

}Position;

二叉樹的順序存儲,元素是放在數組中,注意點要在根節點與孩子結點的2倍關係、以及結點所在層數和序號之間的計算上。

/************************************************************************/
/*      1.二叉樹的順序結構                                                                     */
/************************************************************************/

#define OK 1
#define  ERROR 0
#define  TRUE 1
#define  FALSE 0
#define  MAXSIZE 100    //存儲空間初始分配量
#define  MAX_TREE_SIZE 100  //二叉樹的最大結點數

typedef int Status;
typedef int TElemType;
typedef TElemType SqBiTree[MAX_TREE_SIZE];  //0號單元存儲根節點,使用一個數組存放數據

typedef struct 
{
    int level, order;   //結點的層,本層序號(按照滿二叉樹計算)

}Position;

TElemType Nil=0;    //設整型以0爲空

Status visit_SqBiTree(TElemType c)
{
    printf("%d ",c);
    return OK;
}

//構造空二叉樹T。因爲T是固定數組,不會改變,因此不需要&
Status InitBiTree(SqBiTree T)
{
    int i;
    for (i=0;i<MAX_TREE_SIZE;i++)
        T[i]=Nil;   //初值爲空
    return OK;
}

//按層序的次序輸入二叉樹中結點的值,構造順序存儲的二叉樹T
Status CreateBiTree(SqBiTree T)
{
    int i=0;
    printf("請按照層序輸入結點的值,0表示空節點,輸入999表示結束,結點數<=%d\n",MAX_TREE_SIZE);

    while(i<10)
    {
        T[i]=i+1;
        if (i !=0 && T[(i+1)/2-1]==Nil && T[i]!=Nil)    //此結點不空,無雙親且不是根
        {
            printf("出現無雙親的非根結點%d\n",T[i]);
            exit(ERROR);
        }
        i++;
    }
    while(i<MAX_TREE_SIZE)
    {
        T[i]=Nil;       //將空值賦給T後面的結點
        i++;
    }
    return OK;
}


#define ClearBiTree InitBiTree //在二叉樹的順序存儲結構中,清除和初始化函數一樣

/*  初始條件:二叉樹T存在*/
/*操作結果:若T爲空二叉樹,則返回TRUE;否則返回FALSE*/
Status isBiTreeEmpty(SqBiTree T)
{
    if (T[0]==Nil)  //若根節點爲空,則樹空
        return TRUE;
    else 
        return FALSE;
}


/*初始條件:二叉樹T存在。操作結果:返回T的深度*/
int BiTreeDepth(SqBiTree T)
{
    int i,j=-1;
    for (i=MAX_TREE_SIZE-1; i>=0;i--)   //找到最後一個結點
    {
        if (T[i]!=Nil)
            break;
    }
    i++;
    do 
    {
        j++;
    } while (i>=powl(2,j)); //計算2的j次冪.pow(x,y):計算x的y次方

    return j;
}


/*  初始條件:二叉樹T存在*/
/*  操作結果:當T不爲空,用e返回T的根,返回OK;否則返回ERROR*/
Status Root(SqBiTree T, TElemType *e)
{
    if (isBiTreeEmpty(T))   //先判斷是否爲空
        return ERROR;
    else
    {
        *e =T[0];
        return OK;
    }
}


/*  初始條件:二叉樹T存在,e是T中某個結點*/
/*操作結果:返回處於位置e(層,本層序號)的結點的值*/

TElemType Value(SqBiTree T, Position e)
{
    //2的k-1次方是當前層的第一個元素下標,再加上元素在當前層的序列,-1是得到在該層的準確位置,再進行-1是因爲數組下標從0開始存數據(T[0]存放根節點數據)
    return T[(int)powl(2,e.level-1)+e.order-2];//將層序號轉換爲在數組中存放的下標
}


/*  初始條件:二叉樹T存在,e是T中某個結點的位置*/
/*  操作結果:給處於位置e(層)的結點賦予新值value*/
Status Assign(SqBiTree T, Position e, TElemType value)
{
    int i=(int)powl(2,e.level-1)+e.order-2; //將層號轉換爲矩陣(一位數組)序號
    if (value!=Nil && T[(i+1)/2-1]==Nil)    //value非空;若雙親爲空
        return ERROR;
    else if (value==Nil && (T[i*2+1]!=Nil || T[i*2+2]!=Nil))    //給存在孩子的雙親賦空
        return ERROR;

    T[i]=value; //以上兩種情況都不是,即給T[i]賦值
    return OK;
}


/*初始條件:二叉樹T存在,e是T中的某個結點*/
/*操作結果:若e是T的非根節點,則返回它的雙親,否則返回空*/
TElemType Parent(SqBiTree T, TElemType e)
{
    //判斷是否爲空樹
    if (T[0]==Nil)  
        return Nil;
    for (int i=1; i<=MAX_TREE_SIZE-1; i++)
    {
        if (T[i]==e)    //先找到結點e
        {
            return T[(i+1)/2-1];
        }
    }
    return Nil;     //沒找到e
}


/*初始條件:二叉樹T存在,e是T中的某個結點*/
/*操作結果:返回e的左孩子。若e無左孩子,返回空*/
TElemType LeftChild(SqBiTree T, TElemType e)
{
    //判斷是否爲空樹
    if (T[0]==Nil)
        return Nil;
    for(int i=0;i<=MAX_TREE_SIZE-1;i++)
    {
        if (T[i]==e)
        {
            return T[i*2+1];
        }
    }

    return Nil;//沒找到e
}

/*操作結果,返回右孩子;若無右孩子,返回空*/
TElemType RightChild(SqBiTree T, TElemType e)
{
    if (T[0]==Nil)
        return Nil;
    for (int i=0; i<=MAX_TREE_SIZE-1; i++)
    {
        if (T[i]==e)
        {
            return T[(i+1)*2];
        }
    }
    return Nil;//沒找到e,返回空
}


/*初始條件:二叉樹T存在,e是T中的某個結點*/
/*操作結果:返回e的做兄弟。若e是左孩子或無左兄弟,返回空*/
TElemType LeftBrother(SqBiTree T, TElemType e)
{
    if (T[0]==Nil)
        return Nil;
    for (int i=1; i<=MAX_TREE_SIZE-1;i++)
    {
        if (T[i]==e && i%2==0)
        {
            return T[i-1];
        }
    }

    return Nil;//沒找到e,或者e就是左孩子
}

//返回e的右兄弟
TElemType RightBrother(SqBiTree T, TElemType e)
{
    if (T[0]==Nil)
        return Nil;
    for(int i=1; i<MAX_TREE_SIZE;i++)
    {
        if (T[i]==e && i%2==1 /*&&T[i+1]!=Nil*/)
        {
            return T[i+1];
        }
    }
    return Nil;//沒找到e
}


/*PreOrderTraverse()調用*/
void PreTraverse(SqBiTree T, int e)
{
    visit_SqBiTree(T[e]);
    if (T[2*e+1]!=Nil)      //左子樹不爲空
    {
        PreTraverse(T,2*e+1);
    }

    if (T[2*e+2]!=Nil)  //右子樹不爲空
    {
        PreTraverse(T,2*e+2);
    }
}


/*初始條件:二叉樹存在*/
/*操作結果:先序遍歷T(先序是指根節點先)*/
Status PreOrderTraverse(SqBiTree T)
{
    if (isBiTreeEmpty(T))
        return ERROR;
    PreTraverse(T,0);
    printf("\n");
    return OK;
}

//中序遍歷InOrderTraverse()調用
void InTraverse(SqBiTree T,TElemType e)
{
    if (T[2*e+1]!=Nil)                  //左子樹不爲空,先左子樹
    {
        InTraverse(T,2*e+1);
    }

    visit_SqBiTree(T[e]);               //第二纔是對應根節點

    if (T[2*e+2]!=Nil)                  //第三是右子樹
    {
        InTraverse(T,2*e+2);
    }

}

/*初始條件:二叉樹T存在*/
/*操作結果:中序遍歷*/
Status InOrderTraverse(SqBiTree T)
{
    if (!isBiTreeEmpty(T))
    {
        InTraverse(T,0);
    }
    printf("\n");
    return OK;
}


//後續遍歷PostOrderTraverse()的調用函數
void PostTraverse(SqBiTree T, TElemType e)
{

    if (T[2*e+1]!=Nil)
    {
        PostTraverse(T,2*e+1);
    }

    if (T[2*e+2]!=Nil)
    {
        PostTraverse(T,2*e+2);
    }

    visit_SqBiTree(T[e]);

}

//後序遍歷
Status PostOrderTraverse(SqBiTree T)
{
    if (!isBiTreeEmpty(T))
    {
        PostTraverse(T,0);
    }
    printf("\n");
    return OK;
}


/*層序遍歷二叉樹*/
void LevelOrderTraverse(SqBiTree T)
{
    //注意:要先找到最後一個非空節點的序號,然後再依次遍歷
    int i=MAX_TREE_SIZE-1;
    while(T[i]==Nil)
        i--;
    for (int j=0;j<=i;j++)
    {
        if (T[j]!=Nil)          //只遍歷非空結點
                visit_SqBiTree(T[j]);
    }
    printf("\n");
}

/*逐層、按照本層序號輸出二叉樹*/
void Print(SqBiTree T)
{
    Position p;
    TElemType e;
    for(int j=1;j<=BiTreeDepth(T);j++)
    {
        printf("第%d層:",j);
        for(int i=1;i<=powl(2,j-1);i++)
        {
            p.level=j;
            p.order=i;
            e=Value(T,p);
            if (e!=Nil)
            {
                printf("第%d個:%d",i,e);
            }
        }
        printf("\n");
    }
}

int main()
{
    Status i;
    Position p;
    TElemType e;
    SqBiTree T;
    InitBiTree(T);
    CreateBiTree(T);
    printf("建立二叉樹之後,樹是否爲空?%d(1:是;0:否)\n",isBiTreeEmpty(T));
    printf("樹的深度爲%d\n",BiTreeDepth(T));

    i=Root(T,&e);
    if (i)
    {
        printf("二叉樹的根節點爲%d\n",i);
    }
    else
        printf("二叉樹爲空");

    printf("先序遍歷二叉樹:\n");
    PreOrderTraverse(T);

    printf("中序遍歷二叉樹:\n");
    InOrderTraverse(T);

    printf("後序遍歷二叉樹:\n");
    PostOrderTraverse(T);
    printf("層序遍歷二叉樹:\n");
    LevelOrderTraverse(T);

    printf("修改結點的層號3本層序號2.(第三層的第二個結點)");
    p.level=3;
    p.order=2;
    e=Value(T,p);
    printf(" %d",e);
    e=50;
    Assign(T,p,e);
    printf("修改後,前序遍歷二叉樹:\n");
    PreOrderTraverse(T);

    printf("結點%d的雙親爲%d,左右孩子分別爲%d和%d",e,Parent(T,e),LeftChild(T,e),RightChild(T,e));

    getchar();

}

2.2 二叉樹的鏈式結構:二叉鏈表

首先要構造鏈式表的結構體,如下

//和單鏈表類似。區別在於多了一個指針
typedef struct BiTNode
{
    TelemType data;//存放數據
    struct BiTNode *lchild,*rchild;//構造兩個指針分別指向左子樹和右子樹
}BitNode,*BiTree;       

其次,二叉鏈表在使用的時候,注意力在於根節點與左孩子和右孩子之間的關係。

/************************************************************************/
/* 樹的鏈式存儲結構  :二叉鏈表                                               */
/************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <io.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
typedef int Status;
typedef char TElemType;
TElemType Nil2 =' ';        //字符型以空格爲空,(整型Nil=0)

/******用於構造二叉樹*******/
int index=1;
typedef char String[24];//定義一個字符型數組String,其中0號單元存放串的長度
String str;     //main()函數中用到

Status StrAssignBiTree(String T, char *chars)   //生成一個字符串T,其值等於chars
{
    int i;
    if (strlen(chars) > MAXSIZE)
        return ERROR;
    else
    {
        T[0]=strlen(chars);
        for (i=1; i<=T[0]; i++)
        {
            T[i]=*(chars+i-1);
        }
        return OK;
    }
}

/**************************************/


Status visitBiTree(TElemType e)
{
    printf("%c",e);
    return OK;
}

typedef struct BiTNode          /*定義結點結構*/
{
    TElemType data;                     //結點數據,TElemTypeChar型
    struct BiTNode *lchild, *rchild;        //定義左右孩子指針
}BiTNode, *BiTree;

//構造空的二叉樹T
Status InitBiTree(BiTree *T)
{
    *T =NULL;
    return OK;
}

/*初始條件:二叉樹T存在。操作結果:銷燬二叉樹*/
void DestroyBiTree(BiTree *T)
{
    if (*T)
    {
        if ((*T)->lchild)       //有左孩子
        {
            DestroyBiTree(&(*T)->lchild);       //銷燬左孩子樹
        }

        if ((*T)->rchild)
        {
            DestroyBiTree(&(*T)->rchild);
        }
        free(*T);   //釋放根節點
        *T=NULL;    //空指針賦0
    }

}

#define ClearBiTree DestroyBiTree

/*  按前序輸入二叉樹中結點的值(這裏設置的是一個字符)*/
/*  #表示空樹,構造二叉鏈表表示二叉樹T */
void CreateBiTree(BiTree *T)
{
    TElemType ch;
    ch=str[index++];

    if (ch=='#')        //空樹
    {
        *T=NULL;
    }

    else
    {
        *T=(BiTree)malloc(sizeof(BiTNode));
        if (!*T)
            exit(OVERFLOW);     //表示未分配到合適大小的空間
        (*T)->data=ch;
        CreateBiTree(&(*T)->lchild);        //構造左子樹
        CreateBiTree(&(*T)->rchild);        //構造右子樹
    }
}

/*  初始條件:二叉樹T存在 */
/*  操作結果:若T爲空二叉樹,返回TRUE;否則返回FALSE   */
Status isBiTreeEmpty(BiTree T)
{
    if(T)
        return FALSE;
    else
        return TRUE;
}


/*  初始條件:二叉樹T存在。  操作結果:返回T的深度   */
int BiTreeDepth(BiTree T)
{
    int i,j;
    if(!T)
        return ERROR;
    if (T->lchild)
        i=BiTreeDepth(T->lchild);
    else
        i=0;
    if (T->rchild)
        j=BiTreeDepth(T->rchild);           //因爲不一定是完全二叉樹,所以有可能是各種奇怪的二叉樹。因此既要判斷左子樹,也要判斷右子樹
    else
        j=0;

    return i>j?i+1:j+1;
}


/*  初始條件:二叉樹T存在。 操作結果:返回T的根 */
TElemType Root(BiTree T)
{
    if (!T)
        return Nil2;
    else
        return T->data;
}

/*  初始條件:二叉樹T存在,p指向T中的某個結點  */
/*  操作結果:返回p所指向結點的值 */
TElemType Value(BiTree p)
{
    return p->data;     //
}

//給p所指向的結點賦值爲value
void Assign(BiTree p, TElemType value)
{
    p->data =value;
}

/*初始條件:二叉樹T存在。操作結果:前序遍歷T*/
void PreOrder(BiTree T)
{
    if (!T)
        return;
    printf("%c ",T->data);      //顯示結點數據
    PreOrder(T->lchild);
    PreOrder(T->rchild);
}

/*  初始條件:二叉樹T存在。操作結果:中序遍歷T*/
void InOrder(BiTree T)
{
    if (!T)
        return;
    InOrder(T->lchild);
    printf("%c ",T->data);
    InOrder(T->rchild);
}

/*  後序遍歷*/
void PostOrder(BiTree T)
{
    if(!T)
        return;
    PostOrder(T->lchild);
    PostOrder(T->rchild);
    printf("%c ",T->data);
}




int main()
{
    int i;
    BiTree T;
    TElemType e1;
    InitBiTree(&T);
    StrAssignBiTree(str,"ABDH#K###E##CFI###G#J##");

    CreateBiTree(&T);
    printf("構造空二叉樹後,樹是否爲空?%d(1:空;0:否),樹的深度爲%d\n",isBiTreeEmpty(T),BiTreeDepth(T));

    e1=Root(T);
    printf("樹的根爲%c\n",e1);

    printf("\n前序遍歷結果:");
    PreOrder(T);
    printf("\n中序遍歷結果:");
    InOrder(T);
    printf("\n後序遍歷結果:");
    PostOrder(T);
    ClearBiTree(&T);
    printf("\n清除二叉樹後,樹是否爲空?%d(1:空;0:否),樹的深度爲%d\n",isBiTreeEmpty(T),BiTreeDepth(T));
    i=Root(T);
    if (!i)
        printf("樹空,無根\n");

    getchar();
    return 0;


}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章