樹的三種表示法:雙親表示法、孩子表示法、孩子兄弟表示法

大佬博客傳送門

抽象數據類型:

在這裏插入圖片描述

樹的存儲結構:

利用順序存儲和鏈式存儲的特點,完全可以實現對樹的存儲結構的表示。介紹三種不同的表示法:雙親表示法、孩子表示法、孩子兄弟表示法。

1.雙親表示法

我們假設以一段連續空間存儲樹的結點,同時在每個結點中,附設一個指示器指示其雙親結點到鏈表中的位置。也就是說,每個結點除了直到自己是誰外,還要直到自己的雙親在哪裏。如圖:
在這裏插入圖片描述

其中data就是數據域,存儲結點的信息。而parent是指針域,存儲該結點的雙親在數組中的下標。
雙親表示法的結點結構定義代碼:

//樹的雙親表示法結點結構定義
#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;                     //根節點的位置和結點數
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

有了這樣的結構定義,我們就可以實現雙親定義法了。由於跟結點沒有雙親,所以我們約定根結點的位置域設置爲-1,這就意味着,我們所有結點都直到他雙親的位置。如圖的樹結構和雙親表示法的圖表。
在這裏插入圖片描述

在這裏插入圖片描述

我們可以通過上面快速的找到結點的雙親。但是我們要知道結點的孩子怎麼辦?那就只有遍歷整個結構了。
我們能否改進一下?當然可以,我們可以給結點增加孩子域。

2.孩子表示法

換一種完全不同的想法。由於樹中每個結點可能有很多的子樹,可以考慮用多重鏈表,即每一個結點有多個指針域,其中每個指針指向一個子樹的根節點,我們把這種方法叫做多重鏈表表示法。不過,樹的每個結點的度,也就是它孩子個數是不同的。所以可以設計兩種方案來解決。

方案一

指針域的個數等於樹的度。(樹的度是樹各個結點度的最大值)。(結點擁有的子樹稱爲結點的度)。
在這裏插入圖片描述

如圖,data就是數據域,child1····是指針域,用來指向該結點的孩子結點。

就像6-4-1的樹一樣,我們用這個方法來實現。如圖。
在這裏插入圖片描述
我們可以看到。^這個符號就是代表當前這個指針域並沒有用到。這樣如果樹的各結點的度差距過大的話,顯然非常浪費空間。那我們爲什麼不按需分配空間呢?這樣就有第二種方案了

方案二

每個結點指針域的個數等於該結點的度,我們專門來取一個位置來存儲結點指針域的個數。如圖。
在這裏插入圖片描述

如圖,data就是數據域。degree是度域,也就是存在該結點的孩子結點數。child1····是指針域,用來指向該結點的孩子結點。

那麼對應的樹圖就應該是這樣。
在這裏插入圖片描述
顯然,方案二克服了浪費空間的缺點,但是由於各個結點的鏈表結構是不相同的,在加上要維護結點的度的數值,在運算上顯然有損耗。
能否有更好的方法?既可以減少浪費,又能使結點結構相同。
我們把每一個結點放入順序存儲結構中是合理的,但是每個結點的孩子多少是不確定的,所以我們再對每個結點的孩子建立一個單鏈表來體現他們的關係。
這就是我們的孩子表示法
具體辦法:把每個結點的孩子排列起來,以單鏈表作存儲結構,則n個結點有n個孩子鏈表,如果是葉子結點則此單鏈表爲空。然後n個頭指針有組成一個線性表,採用順序存儲結構,存進一個一維數組。如圖。
在這裏插入圖片描述
爲此,設計兩種結構,一個是孩子鏈表的孩子結點,如圖。
在這裏插入圖片描述

child是數據域,存儲某個結點在表頭數組中的下標。next是指針域,用來存儲某結點的下一孩子結點的指針。

另一個是表頭數組的表頭結點。如圖。
在這裏插入圖片描述

data是數據域,存儲某結點的數據信息。firstchild是頭指針域,存儲該節點的孩子鏈表的頭指針。

以下是孩子表示法的結構定義代碼。

//樹的孩子表示法結點結構定義
#define MAX_TREE_SIZE 100
typedef int TElemType;   //樹結點的數據類型,目前暫定整形
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;                     //根節點的位置和結點數
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我們可以改進一下。把雙親表示法和孩子表示法綜合一下,加一個雙親域。如圖。(雙親孩子表示法)
在這裏插入圖片描述

3.孩子兄弟表示法

任何一棵樹,它的結點的第一個孩子如果是唯一的,它的右兄弟如果存在也是唯一的,因此,我們設置兩個指針,分別指向該結點的第一個孩子和此結點的右兄弟。
結點結構如圖。
在這裏插入圖片描述

data是數據域,firstchild爲指針域,存儲第一個孩子結點的地址,rightsib是指針域,存儲該結點的右兄弟的地址。

結構定義代碼如下.

//樹的孩子兄弟表示法結構定義
typedef struct CSNode{
	TElemType data;
	struct CSNode *firstchild,*rightsib;
}CSNode,*CSTree;
  • 1
  • 2
  • 3
  • 4
  • 5

對於6-4-1的樹來說,這種方法實現的示意圖如圖。
在這裏插入圖片描述
這種方法給查找某結點的某個孩子帶來了方便,只需要通過firstchild 找到此結點的左兒子,然後再通過左兒子找到二弟,一直下去,知道找到具體的孩子。當然,如果想要找到雙親,完全可以增加一個parent 指針域來解決。

參考:
大話數據結構/程傑 著.—北京:清華大學出版社,2011.6

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