1. 樹的存儲結構
樹的存儲方式有多種,即可採用順序存儲結構,又可採用鏈式存儲結構。無論哪種方式都要反映出樹中各結點之間的邏輯關係,下面介紹3種常用的存儲結構
1.1 雙親表示法
這種存儲方式採用喲組連續空間來存儲每個結點,同時在每個結點種增設一個僞指針,指示其雙親結點在數組中的位置。
雙親表示法的存儲結構描述 內聯代碼片
。
#define MAX_TREE-SIZE 100//樹中最多結點數
typedef struct //樹的結點定義
{
ElemType data; //數據元素
int parent; //雙親位置域
}PTNode;
typedef struct //樹的類型定義
{
PTNode nodes[MAX_TREE_SIZE];//雙親表示
int n; //結點樹
}PTree;
該存儲結構利用了每個結點(根結點除外)只有唯一雙親的性質,可以很快得到每個結點的雙親結點,但求結點的孩子時需要遍歷整個結構。
1.2 孩子表示法
孩子表示法是將每個結點的孩子結點都用單鏈錶鏈接起來形成一個線性結構,此時n個結點就有n個孩子鏈表(葉子結點的孩子鏈表爲空表)如下圖
這種存儲方式尋找子女的操作非常直接,而尋找雙親的操作需要遍歷n個結點中孩子鏈表指針域所指向的n個孩子鏈表.
1.3 孩子兄弟表示法
孩子兄弟表示法又稱二叉樹表示法,即以二叉樹表作爲樹的存儲結構孩子兄弟表示法使每個結點包括三部分內容:結點值、指向結點第一個孩子結點的指針,及指向結點下一個兄弟結點的指針。
孩子兄弟表示法的存儲結構描述如下 內聯代碼片
。
typedef struct CSNode{
ElemType data;//數據域
struct CSNode *f_child, *n_sibling;//第一個孩子和右兄弟指針
}CSNode ,*CSTree;
2. 樹、 森林與二叉樹的轉換
由於二叉樹和樹都可以用二叉鏈表作爲存儲結構,因此以一叉鏈表作爲媒介可以導出樹與二叉樹的一個對應關係,即給定一棵樹, 可以找到唯一的一 棵二叉樹與之對應。從物理結構上看,它們的二叉鏈表是相同的,只是解釋不同而已。
樹轉換爲二叉樹的規則:每個結點左指針指向它的第一個孩子, 右指針指向它在樹中的相鄰右兄弟,這個規則又稱“左孩子右兄弟”。由於根結點沒有兄弟,所以對應的二又樹沒有右子樹
樹轉換成:又樹的畫法:①在兄弟結點之間加連線: ②對每個結點。只保留它與第一個孩子的連線,而與其他孩子的連線全部抹掉:③以樹根爲軸心順時針發轉45℃。
森林轉換成二又樹的畫法:①將森林中的每棵樹轉換成相應的二叉樹:②每棵樹的根也可視爲兄弟關係,在每棵樹的根之間加一根連線: ③以第一棵樹的根 爲軸心順時針旋轉45°。
二又樹轉換爲森林的規則:若二叉樹非空,則二叉樹的根及其左子樹爲第一棵樹的 二叉樹形式,故將根的右鏈斷開。二叉樹根的右子樹又可視爲一一個由除第一 棵樹 外的森林轉換後的二叉樹,應用同樣的方法,直到最後只剩棵沒有右子樹的二 叉樹爲止,最後再將每棵二叉樹依次轉換成
樹,就得到了原森林。
3. 樹和森 林的遍歷
樹的遍歷是指用某種方式訪問樹中的每個結點,且僅訪問次。 主要有兩種 方式:
1)先根遍歷。若樹非空,先訪問根結點,再依次遍歷根結點的每棵子樹,遍歷子樹時仍遵循先根後子樹的規則。其遍歷序列與這棵樹相應二叉樹的先序序列相同。
2)後根遍歷。若樹非空,先依次遍歷根結點的每棵子樹,再訪問根結點, 遍歷子樹時仍遵循先子樹後根的規則。其遍歷序列與這棵樹相應二叉樹的中序序列相同。
按照森林和樹相互遞歸的定義,可得到森林的兩種遍歷方法。
1)先序遍歷森林。若森林爲非空,則按如下規則進行遍歷:
●訪問森林中第一棵樹 的根結點。
●先序遍歷第一 棵樹中根結點的子樹森林。
●先序遍歷除去第一棵樹之後剩餘的樹構成的森林。
2)中序遍歷森林。森林爲非空時,按如下規則進行遍歷:
●中序遍歷森林中第一 棵樹的根結點的子樹森林。
●訪問第棵樹的根結點。
●中序遍歷除去第一 棵樹之後剩餘的樹構成的森林。
4. *書的應用-並查集
注:
在採用樹的雙親指針數組表示作爲並查集的存儲表示時,集合元素的編號從0到size-1。其中size是最大無素的個數。下面是並查集主要運算的實現。
並查集的結構定義如下:
#define SIZE 100
intUFSets [SIZE] ;//集合元素數組(雙親指針數組)
並查集的初始化操作(s即爲並查集):
void Initiallint S[]) {
for(int i=0;i<size;i++)//每個自成單元素集合
S[i]=-1;
}
Find操作(函數在並查集S中查找並返回包含元素x的樹的根):
int Find(int s[],int x) {
while(S[x]>=0)//循環尋找x的根
x=S[x] ;
return x;//根的S[]小於0
}
Union操作(函數求兩個不相交子集合的並集):
void Union(int S[],int Root1,int Root2) {
//要求Root1與Root2是不同的,且表示子集合的名字
S[Root2]=Root1;//將根Root2連接到另根Root1 下面
}
應用後續更新:歡迎微信掃碼“MeiXiangDao2020”
領取資料