前幾天被面試官問到了二叉樹,因爲沒有去複習所以回答的很糟糕,數據結構是大二的時候學的,在平時的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 ); //訪問節點數據
}
}
未完待續。