什么是樹
樹是n(n>=0)個結點的有限集。n=0是代表是一棵空樹;
非空樹滿足的條件(n>0)
1、有且僅有一個根節點;
2、當n>1時,其余結點又可以再分為m個有限集,并且分出來的每個有限集本身也是一棵樹,稱作根的子樹。
樹的特征
1、樹是一種遞歸的數據結構;
2、樹也是一種分層的結構;
3、除了樹的根結點外,其余結點都有且僅有一個前驅結點;
4、樹中的所有結點可以有零個或多個后繼結點;
樹的一些概念
1、度
樹中一個結點的孩子結點個數的和稱為度;
樹中結點的最大度數稱為樹的度,即該樹是幾度樹,如果樹中結點的最大度數為m,則稱該樹為m度樹;
度為m的樹,指的是某棵樹中最大度數為m,即其不能為空樹,最少要有m+1個結點;
m叉樹,指的樹中不存在度大于m的樹,即可以小于m甚至沒有,即其可以為空樹,或者退化為鏈表;
2、分支和葉子
度大于零則稱為分支結點,度為零的則稱為葉子結點;
3、高度、深度和層數
層數:是從上往下數的,即樹根為第一層,以此類推;
高度:是從下往上數的,即最下面的葉子結點高度為1,以此類推;
深度:也是從上往下的一個概念;
4、森林
森林是多棵互不相交的樹組成的集合,加上一個根結點可變為樹,故樹與森林和相互轉化;
樹的性質
設樹的結點數為n,度為m,高度為h,樹的總度樹為k(總度樹其實就是邊的個數,因為一個度對應一條邊),則有如下性質;
1、n -1 = k(樹的結點數減一等于該樹的總度數),因為除根外每個結點都只有唯一一個前驅即只有一個邊,于是n個結點有n個邊根結點沒有所以排除;
2、度為m的樹中,第i層最多有m^(i-1)個結點;
3、高度為h的m叉樹至多有(m^h - 1)/(m -1)個結點,計算方式就是根據2等比數列求和;
4、高度為h的度為m的樹至少有h+m-1個結點;
5、有n個結點的m叉樹的最小高度為[logm(n(m-1)+1)],根據3取對數可得;
樹的存儲結構
雙親表示法
這種存儲方式是使用順序存儲的結構,在結點中又增加了一個用于存儲父結點的指針,即父結點在數組中的位置,根結點在數組中的位置為0,其父結點值設置為-1;
#define Max_Size 100
typedef struct TreeNode{
ElemType data;
int parentIndex;
} TreeNode;
typedef struct Tree{
TreeNode nodes[Max_Size];
int length;
} Tree;
這種存儲方式的優點是查詢結點的雙親很方便;
缺點正好相反,查找孩子結點就比較麻煩需要遍歷這個數組;
孩子表示法
這種存儲方法是把順序表和鏈表結合在一起的存儲方法,這種存儲的思想也很重要;
這種存儲方式是,用數組順序存儲各個節點,每個結點中又多加一個用于存儲孩子結點鏈表頭的指針,即將各孩子在數據存儲的位置用鏈表串起來;
typedef struct LinkNode{
int childIndex;
struct LinkNode *next;
}
typedef struct TreeNode{
ElemType data;
struct TreeNode *firstChild;
} TreeNode;
typedef struct Tree {
TreeNode nodes[Max_Size];
int length;
}
這種方式方便尋找孩子結點,但是需要父結點時需要遍歷數組;
孩子兄弟表示法
這種存儲方法又稱為二叉樹表示法,是用鏈表表示的存儲方法;
該存儲方法包含三個字段即,結點值、指向第一個孩子結點的指針(左孩子)、右指針指向兄弟結點;
typedef struct TreeNode {
ElemType data;
struct TreeNode *firstChild, *nextSibling;
} TreeNode, *Tree;
這種存儲方法最大的優勢就是,將我們不太熟悉的樹結構,轉化為熟悉的二叉樹結構;
而且查詢孩子結點是很方便的,缺點是不容易查找其父結點;