超清晰-數據結構之樹與二叉樹

  前幾天被面試官問到了二叉樹,因爲沒有去複習所以回答的很糟糕,數據結構是大二的時候學的,在平時的web開發我能用到的機會其實不多,所以也沒有去整理,但是數據結構也是程序的靈魂架構,是需要認真研究的,故在此繼續進行整理複習。

  一、什麼是樹?

1.1  樹是n(n>=0)個結點的有限集,根據結點數可分爲空樹(n=0)或非空樹(n>0),對於非空的樹T,有着兩個定義:

(1)有且僅有一個稱之爲根的結點;

(2)除根結點以外的其餘結點可分爲m(m>0)個互不相交的有限集T1,T2,...,Tm,其中每個集合本身又是一個樹,並且又稱之爲根的子樹。

常見的樹如下圖:

1.2 常見的樹基本術語:

(1)結點:樹中的一個獨立單位。包含一個數據元素及若干指向其子樹的分支,如圖中的每個字母都是一個結點。

(2)結點的度:結點所擁有的子樹數稱爲結點的度,如D的度爲3,E的度數爲1。

(3)樹的度:樹的度是樹內各結點度的最大值,上圖的樹的度爲3.

(4)葉子:度爲0的結點稱爲葉子或終端結點。如上圖的G,H,I,J,F.

(5)非終端結點:度不爲0的結點稱爲非終端結點或分支結點。除根結點之外,也稱爲內部結點。如上圖的A,B,C,D,E.

(6)雙親和孩子:若一個結點含有子結點,則這個結點稱爲其子節點的雙親節點。如上圖的D的雙親結點爲B

(7)兄弟:具有同個雙親的結點互爲兄弟結點。如上圖的G,I,H

(8)祖先:從根到該結點所經分支上的所有結點。如上圖的J的祖先爲A,C,E

(9)子孫:以某個結點爲根的子樹中的任一結點都是該根結點的子孫。如上圖B的子孫有D,G,H,I

(10)層次:結點的層次從根開始定義,如上圖的層次說明。

(11)堂兄弟:雙親在同一層的結點互爲堂兄弟。例如結點D的堂兄弟爲E,F.

(12)樹的深度:樹中結點的最大層次稱之爲樹的深度或高度。如上圖的深度爲4.

(13)有序樹和無序樹:如果將樹中結點的各子樹看成從左至右是由次序的,則稱該樹的爲有序樹,否則爲無序樹。

 

二、什麼是二叉樹?

 2.1  二叉樹是一種特殊的樹,主要有着以下兩個特點:

(1)有且僅有一個稱之爲根的結點;

(2)除根結點以外的其餘結點分爲兩個互不相交的子集T1和T2,分別稱爲T的左子樹和右子樹,且T1和T2本身又都是二叉樹。

2.2 二叉樹的遍歷

三種遍歷方式:

①先序遍歷(根左右)②中序遍歷(左根右)③後序遍歷 (左右根)        (這個面試有問到。)

 (1)先序遍歷:1.訪問根結點  2.先序遍歷左子樹  3.先序遍歷右子樹

如上圖的先序遍歷爲:ABDGCEF

(2)中序遍歷:1.中序遍歷左子樹 2.訪問根結點 3.中序遍歷右子樹

如上圖的中序遍歷爲:DGBAECF

(3)後序遍歷:1.後序遍歷左子樹 2.後序遍歷右子樹  3.訪問根結點

如上圖的後序遍歷爲:GDBEFCA

三、 二叉樹的存儲結構

3.1 ①順序存儲結構  ②鏈式存儲結構

(1)順序存儲結構

實際上就是用一個一維數組按照自上而下,自左至右的將每一層的結點放入數組中,

二叉樹的順序存儲表示:

#define MAXSIZE 100
typedef TElemType SqBiTree[MAXSIZE];
SqBiTree bt;

這時候如果你對c的typedef不熟悉的話可能不是很明白上面的這種寫法。實際上這裏用到了typedef定義數組的方式。

假設爲 typedef int sqBiTree[10]  ,SqBiTree bt ,相當於定義一個int bt[10].

如上圖的圖示順序存儲結構差不多是這樣的。

圖畫的很醜將就點看吧,其中0表示爲空,我們可以很直觀就可以看出這種存儲方式的弊端,如果二叉樹不是完全二叉樹的話,是會有很大的空間浪費的。這種方式唯一的特點就是比較簡單容易理解,但是實際上,我們很少會使用順序存儲方式,

(2)鏈式存儲方式

實際上就是一個鏈表,鏈表的結點至少得包含三個域:數據域和左右指針域(爲了方便找到結點的雙親,還可以在結點的結構中增加一個指向其雙親結點的指針域)

二叉樹的鏈式存儲表示:

typedef struct BiTNode{
  TElemType data;        //結點的數據域
  struct BiTNode *lchild,*rchild; //左右孩子指針
}BiTNode,*BiTree;

把上面的圖複製下來:

3.2 二叉樹的三種遍歷僞代碼實現(遞推形式)

先序:

void preOrder(BitTree t)      //先序遍歷
{
    if(t)             //樹不爲空
    {
        visit(t->data );        //訪問節點數據,自定義訪問函數visit
        preOrder (t->lchild );      //遞歸遍歷左子樹
        preOrder (t->rchild );      //遞歸遍歷右子樹
    }
}

中序:

void inOrder(BitTree t)       //中序遍歷
{ 
    if(t)          //樹不爲空
    {
        inOrder (t->lchild );
        visit(t->data );        //訪問節點數據
        inOrder (t->rchild );
    }
}

後序:

void postOrder(BitTree t)     //後序遍歷
{
    if(t)           //樹不爲空
    {
        postOrder (t->lchild );
        postOrder (t->rchild );
        visit(t->data );        //訪問節點數據
    }
}

未完待續。

 

 

 

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