數據結構入門-樹的遍歷以及二叉樹的建立

樹定義:node

  1. 有且只有一個稱爲根的節點
  2. 有若干個互不相交的子樹,這些子樹自己也是一個樹

通俗的講:數據庫

  1. 樹是有結點和邊組成,
  2. 每一個結點只有一個父結點,但能夠有多個子節點
  3. 但有一個節點例外,該節點沒有父結點,稱爲根節點

1、專業術語

結點、父結點、子結點、根結點ui

深度:從根節點到最底層結點的層數稱爲深度,根節點第一層操作系統

葉子結點:沒有子結點的結點指針

非終端節點:其實是非葉子結點code

度:子結點的個數成爲度對象

2、樹的分類

通常樹:任意一個結點的子結點的個數都不受限制繼承

二叉樹:任意一個結點的子結點個數最可能是兩個,且子結點的位置不可更改遞歸

二叉數分類:進程

  1. 通常二叉數
  2. 滿二叉樹:在不增長樹層數的前提下,沒法再多添加一個結點的二叉樹
  3. 徹底二叉樹:若是隻是刪除了滿二叉樹最底層最右邊的連續若干個結點,這樣造成的二叉樹就是徹底二叉樹

森林:n個互不相交的樹的集合

3、樹的存儲

二叉樹存儲

連續存儲(徹底二叉樹)

優勢:查找某個結點的父結點和子結點(也包括判斷有沒有子結點)速度很快

缺點:耗用內存空間過大

鏈式存儲

通常樹存儲

  1. 雙親表示法:求父結點方便

  2. 孩子表示法:求子結點方便

  3. 雙親孩子表示法:求父結點和子結點都很方便

  4. 二叉樹表示法:把一個通常樹轉化成一個二叉樹來存儲,

    • 具體轉換方法:
    • 設法保證任意一個結點的左指針域指向它的第一個孩子,右指針域指向它的兄弟,只要能知足此條件,就能夠把一個通常樹轉化爲二叉樹

    一個普通樹轉換成的二叉樹必定沒有右子樹

森林的存儲

先把森林轉化爲二叉樹,再存儲二叉樹

4、樹的遍歷

先序遍歷:根左右

先訪問根結點,再先序訪問左子樹,再先序訪問右子樹

先序01.png

先序02.png

中序遍歷:左根右

中序遍歷左子樹,再訪問根結點,再中序遍歷右子樹

中序01.png

中序02.png

後續遍歷:左右根

後續遍歷左子樹,後續遍歷右子樹,再訪問根節點

後序01.png

5、已知兩種遍歷求原始二叉樹

給定了二叉樹的任何一種遍歷序列,都沒法惟一肯定相應的二叉樹,可是若是知道了二叉樹的中序遍歷序列和任意的另外一種遍歷序列,就能夠惟一地肯定二叉樹

已知先序和中序求後序

先序:ABCDEFGH

中序:BDCEAFHG

求後序: 這個本身畫個圖體會一下就能夠了,很是簡單,這裏簡單記錄一下

  1. 首先根據先序肯定根,上面的A就是根
  2. 中序肯定左右,A左邊就是左樹(BDCE),A右邊就是右樹(FHG)
  3. 再根據先序,A左下面就是B,而後根據中序,B左邊沒有,右邊是DCE
  4. 再根據先序,B右下是C,根據中序,c左下邊是D,右下邊是E,因此整個左樹就肯定了
  5. 右樹,根據先序,A右下是F,而後根據中序,F的左下沒有,右下是HG,
  6. 根據先序,F右下爲G,而後根據中序,H在G的左邊,因此G的左下邊是H

實例01.png

再來一個例子,和上面的思路是同樣的,這裏就不詳細的寫了

先序:ABDGHCEFI

中序:GDHBAECIF

實例02.png

已知中序和後序求先序

中序:BDCEAFHG

後序:DECBHGFA

這個和上面的思路是同樣的,只不過是反過來找,後序找根,中序找左右

例子03.png

樹簡單應用

樹是數據庫中數據組織一種重要形式

操做系統子父進程的關係自己就是一棵樹

面嚮對象語言中類的繼承關係

哈夫曼樹

6、二叉樹的建立

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

typedef struct Node
{
    char data;
    struct Node * lchild;
    struct Node * rchild;
}BTNode;

/*
二叉樹創建
*/
void BuildBT(BTNode ** tree)
{
    char ch;
    scanf("%c" , &ch); // 輸入數據
    if(ch == '#')  // 若是這個節點的數據是#說明這個結點爲空
        *tree = NULL;
    else
    {
        *tree = (BTNode*)malloc(sizeof(BTNode));//申請一個結點的內存
        (*tree)->data = ch; // 將數據寫入到結點裏面
        BuildBT(&(*tree)->lchild); // 遞歸創建左子樹
        BuildBT(&(*tree)->rchild); // 遞歸創建右子樹
    }
}

/*
二叉樹銷燬
*/
void DestroyBT(BTNode *tree) // 傳入根結點
{
    if(tree != NULL)
    {
        DestroyBT(tree->lchild);
        DestroyBT(tree->rchild);
        free(tree);  // 釋放內存空間
    }
}

/*
二叉樹的先序遍歷
*/
void Preorder(BTNode * node)
{
    if(node == NULL)
        return;
    else
    {
        printf("%c ",node->data );
        Preorder(node->lchild);
        Preorder(node->rchild);
    }
}

/*
二叉樹的中序遍歷
*/
void Inorder(BTNode * node)
{
    if(node == NULL)
        return;
    else
    {
        
        Inorder(node->lchild);
        printf("%c ",node->data );
        Inorder(node->rchild);
    }
}


/*
二叉樹的後序遍歷
*/
void Postorder(BTNode * node)
{
    if(node == NULL)
        return;
    else
    {
        
        Postorder(node->lchild);
        Postorder(node->rchild);
        printf("%c ",node->data );
    }
}

/*
二叉樹的高度
樹的高度 = max(左子樹高度,右子樹高度) +1
*/
int getHeight(BTNode *node)
{
    int Height = 0;
    if (node == NULL)
        return 0;
    else
    {
        int L_height = getHeight(node->lchild);
        int R_height = getHeight(node->rchild);
        Height = L_height >= R_height ? L_height +1 : R_height +1;
    }

    return Height;
}


int main(int argc, char const *argv[])
{
    BTNode * BTree; // 定義一個二叉樹
    printf("請輸入一顆二叉樹先序序列以#表示空結點:");
    BuildBT(&BTree);

    printf("先序序列:");
    Preorder(BTree);
    printf("\n中序序列:");
    Inorder(BTree);
    printf("\n後序序列:");
    Postorder(BTree);

    printf("\n樹的高度爲:%d" , getHeight(BTree));
    return 0;
}
// ABC##DE##F##G##
相關文章
相關標籤/搜索