/* 樹(Tree) 6.3 樹的抽象數據類型 相對於線性結構,樹的操作就完全不同了,這里我們給出一些基本和常用操作。 ADT 樹(tree) Data 樹是由一個根節點和若干棵子樹構成。樹中結點具有相同數據類型及層次關系。 Operation InitTree(*T); 構造空樹T DestroyTree(*T); 銷毀樹T CreateTree(*T, definition); 按definition中給出樹的定義來構造樹 ClearTree(*T); 若樹T存在,則將樹T清空為空樹 TreeEmpty(T); 若T為空樹,返回true,否則返回false TreeDepth(T); 返回T的深度 Root(T); 返回T的根結點 Value(T, cur_e); cur_e是樹T中一個結點,返回此結點的值 Assign(T, cur_e, value); 給樹T的結點cur_e賦值為value Parent(T, cur_e); 若cur_e是樹T的非根結點,則返回它的雙親,否則返回空 LeftChild(T, cur_e); 若cur_e是樹T的非葉結點,則返回它的雙親,否則返回空 RightSibling(T, cur_e); 若cur_e有右兄弟,則返回它的右兄弟,否則返回空 InsertChild(*T, *p, i, c); 其中p指向樹T的某個結點,i為所指結點p的度加上1,非空樹c與T不相交, 操作結果為 插入c為樹T中p指結點的第i棵子樹 DeleteChild(*T, *p, i); 其中p指向樹T的某個結點,i為所指結點p的度, 操作結果為 刪除T中p所指結點的第i棵子樹 endADT */ /* 6.4 樹的存儲結構 說到存儲結構,就會想到我們前面章節講過的順序存儲和鏈式存儲兩種結構。 先來看看順序存儲結構,用一段地址連續的存儲單元依次存儲線性表的數據元素。這對於線性表來說是很自然的, 對於樹這樣一對多的結構呢? 樹中某個結點的孩子可以有多個,這就意味着,無論按何種順序將樹中所有結點存儲到數組中,結點的存儲位置 都無法直接反映邏輯關系,你想想看,數據元素挨個存儲,誰是誰的雙親,誰是誰的孩子呢?簡單的存儲結構是不能 滿足樹的實現要求的。 不過充分利用順序存儲和鏈式存儲結構的特點,完全可以實現對樹的存儲結構的表示。我們這里要介紹三種不同的 表示法:雙親表示法、孩子表示法、孩子兄弟表示法。 */ /*6.4.1 雙親表示法*/ //樹的雙親表示法結點結構定義 #define MAX_TREE_SIZE 100 //樹節點的數據類型,目前暫定為整形 typedef int TElemType; //節點結構 typedef struct PTNode { //結點數據 TElemType data; //雙親位置,通常講的父節點 int parent; } PTNode; //樹結構 typedef struct { //結點數組 PTNode nodes[MAX_TREE_SIZE]; //跟的位置和結點數 int r, n; } PTree; /*6.4.2 孩子表示法*/ /* 具體的辦法是,把每個結點的孩子結點排列起來,以單鏈表作存儲結構,則n個結點有n個孩子鏈表,如果是 葉子結點則此單鏈表為空。然后n個頭指針又組成一個線性表,采用順序存儲結構,存放進一個一維數組中。 見原書 284頁 圖6-4-4 為此,設計兩種節點結構, 一個是 孩子鏈表的孩子結點;其中child是數據域,用來存儲某個結點在表頭數組中 的下標。next是指針域,用來存儲指向某節點的下一個孩子結點的指針。 另一個 是表頭數組的表頭結點,其中data是數據域,存儲某結點的數據信息。firstchild是頭指針域,存儲 該結點的孩子鏈表的頭指針。 */ /*樹的孩子表示法結構定義*/ #define MAX_TREE_SIZE 100 //孩子結點 typedef struct CTNode { int child; struct CTNode *next; } *ChildPtr; //表頭結構 typedef struct { TElemType data; ChildPtr firstchild; } CTBox; //樹結構 typedef struct { /*結點數組*/ CTBox nodes[MAX_TREE_SIZE]; int r,n; } CTree; /* 這樣的結構對於我們要查找某個結點的某個孩子,或者找某個結點的兄弟,只需要查找這個節點的孩子單鏈表即可 但是,這也存在着問題,我如何知道某個結點的雙親是誰呢?比較麻煩,需要整棵樹遍歷才行 ,難道就不可以把雙親 表示法和孩子表示法綜合一下嗎? 當然可以了 看原書 圖6-4-5(雙親孩子表示法) */ /* 6.4.3 孩子兄弟表示法 剛才我們分別從雙親的角度和孩子的角度研究樹的存儲結構,如果我們從樹結點的兄弟的角度考慮又會如何呢? 當然,對於樹這樣的層級結構來說,只研究結點的兄弟是不行的,我們觀察后發現,任意一棵樹,他的結點的第一個 孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此我們設置兩個指針,分別指向該結點的第一個孩子和 此結點的右兄弟。 */ //結構定義代碼如下 //樹的孩子兄弟表示法結構定義 typedef struct CSNode { TElemType data; struct CSNode *firstchild,*rightsib; } CSNode, *CSTree; /* 這種表示法,給查找某個結點的某個孩子帶來了方便,只需要通過firstchild找到此結點的長子,然后通過長子結點 的rightsib找到它的二弟,接着一直下去,直到找到具體的孩子。當然,如果想找某個結點的雙親,這個表示法 也是有缺陷的,那怎么辦呢? 呵呵,如果真的有必要,完全再增加一個parent指針域來解決快速查找雙親的問題,這里就不細談了。 其實這個表示法的最大好處是它把一顆復雜的樹變成了一顆二叉樹。 */