一. 概述
樹的存儲結構應用範圍極爲廣泛,我所瞭解的,如Linux操作系統的目錄結構,DNS域名的存儲,多路複用中的epoll利用的紅黑樹…
那麼,什麼是樹嘞?
這就是一顆樹,下面引出一些概念
- 空樹
上面的每一個圓圈表示一個結點,用n來表示結點個數,當n等於0是則代表樹是空樹
- 根節點
當n>0時,樹有且僅有一個根節點,如圖一所示的A結點
- 結點關係
A是B的雙親結點,B是A的孩子結點,B,C是兄弟,E,F是兄弟
- 樹的度
也是樹的寬度,即結點的分支樹的個數,如圖一中A結點的度爲3,B結點的度爲2;以組成該樹各節點中最大的度作爲樹的度,圖一樹的度爲3,樹種度爲0的結點稱爲葉子結點或終端結點,度不爲0的結點稱爲分支結點或非終端結點,除終端結點外的分支結點稱爲內部結點
- 樹的深度
組成該樹各結點的最大層次,圖中的樹深度爲4
- 森林
若干顆互不相交的樹的集合{T1,T2,T3}
- 有序樹
如果將樹中結點的各子樹看成從左至右是有次序的,不能互換的,則稱該樹爲有序樹,否則稱爲無序樹
二. 樹的實現
前面學習了順序存儲結構,鏈式存儲結構,樹的實現也需要用到二者,只是,對於樹來說,又有三種表示法,分別是雙親表示法,雙親孩子表示法,孩子兄弟表示法,下面就通過樹的實現來體會這些名字的由來.
2.1 雙親表示法
雙親表示法,即以雙親結點爲索引的個關鍵詞的一種存儲方式,下面來看利用順序存儲的實現:
我們假設以一組連續空間存儲樹的結點,同時在每個結點中,即存儲了本節點的值,還存儲了雙親結點的位置,也就是說結點除了知道“我是誰”,還知道“我的雙親是誰”。
#define MAX_TREE_SIZE 100
typedef int ElemType;
typedef struct PTNode
{
ElemType data; //存儲結點的數據
ElemType parent; //存儲雙親結點的下標
}PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE]; //存儲結點的數組
int r; //根的位置
int n; //結點個數
}PTree;
來看下面這顆樹:
再來看用我們上述方法表示的結果:
需要注意,這裏是按照層次遍歷來表示的(關於遍歷方式後面博客會繼續總結)
想象一下,既然是結構體,我們還可以存儲更多東西,例如在結點的結構體PTNode中接入孩子結點的位置,加入兄弟結點的位置,只要是便於樹的操作,完全可以開放性的設計!
2.2 雙親孩子表示法
結合雙親表示法,利用鏈式存儲,則有下面結構
分析完圖六,我們再來看雙親孩子表示法的實現:
#define MAX_TREE_SIZE 100
typedef char ElemType;
typedef struct CTNode
{
int child; //孩子結點的下標
struct CTNode *next; //指向孩子的指針
}*ChildPtr;
typedef struct ctbox
{
ElemType data; //結點數據
int parent; //結點下標
ChildPtr firstchild; //指向第一個孩子的指針
}CTBox;
typedef struct pcTree
{
CTBox nodes[MAX_TREE_SIZE];
int r;
int n;
}PCTree;
關於樹的其他知識,後續繼續總結!