樹形結構--二叉樹以及二叉樹的遍歷(十七)

在這裏插入圖片描述


一.二叉樹

1.二叉樹的定義

把滿足以下條件的樹結構稱爲二叉樹:

1.每個結點的度都不大於2.

2.每個結點的孩子結點次序不能任意顛倒。


2.二叉樹的性質

性質1:在二叉樹的第k層上,最多有2^(k-1)(k≥1)個結點。

性質2:深度爲m的二叉樹最多有2m-1(m≥1)個結點。

性質3:在任意一棵二叉樹中,如果其終端結點數爲n0,度爲2的結點數爲n2,則n0=n2+1。

性質4:具有n個結點的二叉樹,其深度至少爲〔log2n〕+1,其中〔log2n〕表示取log2n的整數部分。

性質5:如果對一棵有n個結點的完全二叉樹按照從上到下和從左到右的順序對所有結點進行從1開始順序編號,則對於任意的序號爲i的結點有:

①如 i =1,則結點i是二叉樹的根,無雙親,如 i > 1,則序號爲i的結點的雙親結點序號爲i/2。

②如 2i > n,則序號爲i的結點無左孩子,如 2i ≤ n,則序號爲i的結點的左孩子結點的序號爲2i。

③如 2i+1 > n,則序號爲i的結點無右孩子,如 2i+1 ≤ n,則序號爲i的結點的右孩子結點的序號爲2i+1。


3.二叉樹的存儲結構

二叉樹的結構是非線性的,每一個結點最多可有兩個後繼。二叉樹的存儲結構分爲順序存儲結構和鏈式存儲結構。


1).順序存儲結構

順序存儲結構可以用一維數組來實現,如下圖:
在這裏插入圖片描述


可以看出,當二叉樹爲完全二叉樹時,這種存儲結構很方便,而且不浪費空間,但是對於一般的二叉樹,必須用“虛結點”將其補成一個完整的完全二叉樹來存儲,這就造成了空間浪費,如下圖:
在這裏插入圖片描述
因此,順序存儲一般適用於完全二叉樹,既然順序存儲不能滿足對二叉樹的存儲需求,那麼可以使用鏈式存儲,如下圖。


2).鏈式存儲結構

在這裏插入圖片描述
對於任意二叉樹,每個結點只有一個雙親結點(根除外),最多有兩個孩子,便可以設計成上圖所示結構:【lchind data rchild】。該二叉樹實現方式又稱爲二叉鏈表。


3).結點代碼實現

二叉鏈表結點結構代碼實現如下:

typedef struct Node
{
    DataType data;
    struct Node * LChild;
    struct Node * RChild;
}BiTNode,*BiTree;

二.二叉樹的遍歷(重點)

1.遍歷理論過程

在這裏插入圖片描述
如果用LDR表示遍歷左子樹,根結點,右子樹,則有如下6種遍歷順序:

①訪問根,遍歷右子樹,遍歷左子樹。記作DRL

②訪問根,遍歷左子樹,遍歷右子樹。記作DLR

③遍歷左子樹,訪問根結點,遍歷右子樹。記作LDR

④遍歷右子樹,訪問根結點,遍歷左子樹。記作RDL

⑤遍歷左子樹,遍歷右子樹,訪問根結點。記作LRD

⑥遍歷右子樹,遍歷左子樹,訪問根結點。記作RLD

如果規定按先左後右的順序遍歷,則只剩下三種:DLR , LDR , LRD。

然後根據對根訪問順序的不同,分別稱DLR爲前序遍歷,LDR爲中序遍歷,LRD爲後序遍歷。


在這裏插入圖片描述
對於上述的二叉樹:
前序遍歷順序:A B D E C F G
中序遍歷順序:D B E A F C G
後序遍歷順序:D E B F G C A

寫成這樣,我覺得會更有助於萌新的理解:

前序遍歷順序:(A)    (B (DE) )    (C (FG) )
中序遍歷順序:((D) B (E))    (A)    ((F) C (G))
後序遍歷順序:( (DE) B)    ( (FG) C)    (A)

先將大頭寫下來然後進行填寫,類似於填空,但是僅限於幫助你理解遍歷順序,而不是讓你使用這個方法記憶遍歷順序,我們應該通過輔助工具來幫助我們真正瞭解。


下面再出一個練練手:
在這裏插入圖片描述

試着寫一寫是不是和下面的答案一樣呢,如果一樣,說明你學會了!
前序遍歷:A B D F G C E H
中序遍歷:B F D G A C E H
後序遍歷:F G D B H E C A

下面用代碼來實現各種遍歷。


2.前序遍歷

void PreOrder(BiTree root)
{ // root爲指向二叉樹或某一樹的根結點
    if(root!=NULL)
    {
        Visit(root->data); // 訪問根結點,顯示數據結點
        PreOrder(root->LChild);// 遍歷左子樹
        PreOrder(root->RChild);// 遍歷右子樹
    }
}

3.中序遍歷

void PreOrder(BiTree root)
{
    if(root!=NULL)
    {
        PreOrder(root->LChild);
        Visit(root->data)
        PreOrder(root->RChild);
    }
}

4.後序遍歷

void PreOrder(BiTree root)
{
    if(root!=NULL)
    {        
        PreOrder(root->LChild);
        PreOrder(root->RChild);
        Visit(root->data);
    }
}

雖然理論知識對於二叉樹的遍歷很複雜,但是由於二叉樹是一種遞歸定義的結構,先序,中序,後序,便是遞歸定義的。故採用遞歸的方式遍歷二叉樹的代碼量很少。


若有錯誤,歡迎指正批評,歡迎評論。
每文一句:沒有人會爲你的貧窮負責,卻有人爲你的富有而喝彩!所以不要活在別人的嘴巴里,做好自己!有路,就大膽地去走;有夢,就大膽地飛翔;前行的路,不怕萬人阻擋,只怕自己投降!

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