二叉樹的簡單介紹以及二叉樹的存儲結構
什么是二叉樹?
二叉樹是遞歸定義的,其結點有左右子樹之分,邏輯上二叉樹有五種基本形態:

二叉樹的術語:
二叉樹的主要性質
1.一顆非空二叉樹的第i層上最多有2i-1個結點(i>=1)。
2.一顆深度為k的二叉樹中,最多具有2k-1個結點。
3.對於一顆非空二叉樹,如果葉子結點樹為n0,度數為2的二叉樹結點為n2,則有n0=n2+1;
4.具有n個結點的完全二叉樹的深度k為[log2n]+1。
二叉樹的存儲結構
二叉樹是非線性結構,即每個數據結點至多只有一個前驅,但可以有多個后繼。
它可采用順序存儲結構和鏈式存儲結構。而鏈式存儲結構有可以分為二叉鏈表存儲結構、 三叉鏈表存儲結構(帶雙親指針的二叉鏈表存儲結構)
1.順序存儲結構
二叉樹的順序存儲,就是用一組連續的存儲單元存放二叉樹中的結點。因此,必須把二叉樹的所有結點安排成為一個恰當的序列,結點在這個序列中的相互位置能反映出結點之間的邏輯關系,用編號的方法從樹根起,自上層至下層,每層自左至右地給所有結點編號,缺點是有可能對存儲空間造成極大的浪費,在最壞的情況下,一個深度為k且只有k個結點的右單支樹需要2k-1個結點存儲空間。依據二叉樹的性質,完全二叉樹和滿二叉樹采用順序存儲比較合適,樹中結點的序號可以唯一地反映出結點之間的邏輯關系,這樣既能夠最大可能地節省存儲空間,又可以利用數組元素的下標值確定結點在二叉樹中的位置,以及結點之間的關系。圖5-5(a)是一棵完全二叉樹,圖5-5(b)給出的圖5-5(a)所示的完全二叉樹的順序存儲結構。
(a) 一棵完全二叉樹 (b) 順序存儲結構
圖5-5 完全二叉樹的順序存儲示意圖
對於一般的二叉樹,如果仍按從上至下和從左到右的順序將樹中的結點順序存儲在一維數組中,則數組元素下標之間的關系不能夠反映二叉樹中結點之間的邏輯關系,只有增添一些並不存在的空結點,使之成為一棵完全二叉樹的形式,然后再用一維數組順序存儲。如圖5-6給出了一棵一般二叉樹改造后的完全二叉樹形態和其順序存儲狀態示意圖。顯然,這種存儲對於需增加許多空結點才能將一棵二叉樹改造成為一棵完全二叉樹的存儲時,會造成空間的大量浪費,不宜用順序存儲結構。最壞的情況是右單支樹,如圖5-7 所示,一棵深度為k的右單支樹,只有k個結點,卻需分配2k-1個存儲單元。
(a) 一棵二叉樹 (b) 改造后的完全二叉樹
(c) 改造后完全二叉樹順序存儲狀態
圖5-6 一般二叉樹及其順序存儲示意圖
(a) 一棵右單支二叉樹 (b) 改造后的右單支樹對應的完全二叉樹
(c) 單支樹改造后完全二叉樹的順序存儲狀態
圖5-7 右單支二叉樹及其順序存儲示意圖
結構5-1二叉樹的順序存儲
1 #define Maxsize 100 //假設一維數組最多存放100個元素 2 typedef char Datatype; //假設二叉樹元素的數據類型為字符 3 typedef struct 4 { Datatype bt[Maxsize]; 5 int btnum; 6 }Btseq;
2.二叉鏈式存儲結構
二叉樹的鏈式存儲結構是指,用鏈表來表示一棵二叉樹,即用鏈來指示元素的邏輯關系。
通常的方法是鏈表中每個結點由三個域組成,數據域和左右指針域,左右指針分別用來給出該結點左孩子和右孩子所在的鏈結點的存儲地址。其結點結構為:
其中,data域存放某結點的數據信息;lchild與rchild分別存放指向左孩子和右孩子的指針,當左孩子或右孩子不存在時,相應指針域值為空(用符號∧或NULL表示)。利用這樣的結點結構表示的二叉樹的鏈式存儲結構被稱為二叉鏈表,如圖5-8所示。
(a) 一棵二叉樹 (b) 二叉鏈表存儲結構
圖5-8 二叉樹的二叉鏈表表示示意圖
3.三叉鏈表存儲結構
為了方便訪問某結點的雙親,還可以給鏈表結點增加一個雙親字段parent,用來指向其雙親結點。每個結點由四個域組成,其結點結構為:
這種存儲結構既便於查找孩子結點,又便於查找雙親結點;但是,相對於二叉鏈表存儲結構而言,它增加了空間開銷。利用這樣的結點結構表示的二叉樹的鏈式存儲結構被稱為三叉鏈表。
圖5-9給出了圖5-8 (a)所示的一棵二叉樹的三叉鏈表表示。
圖5-9二叉樹的三叉鏈表表示示意圖
盡管在二叉鏈表中無法由結點直接找到其雙親,但由於二叉鏈表結構靈活,操作方便,對於一般情況的二叉樹,甚至比順序存儲結構還節省空間。因此,二叉鏈表是最常用的二叉樹存儲方式。
結構5-2二叉樹的鏈式存儲
#define datatype char //定義二叉樹元素的數據類型為字符 typedef struct node //定義結點由數據域,左右指針組成 { Datatype data; struct node *lchild,*rchild; }Bitree;