非線性結構——樹定義
- 專業定義:
- 有且只有一個稱爲根的節點。
- 有若干個互不相交的子樹,這些子樹本身也是一棵樹。
- 通俗地講:
- 樹是由節點和邊組成。
- 每個節點只有一個父節點,但可以有多個子節點。
- 但有一個節點例外,該節點沒有父節點,此節點稱爲根節點。
- 專業術語:
- 節點
- 父節點
- 子節點
- 子孫
- 堂兄弟
- 深度:從根節點到最底層節點之間的層數稱之爲深度。
- 葉子結點:沒有子節點的節點。
- 非終端節點:實際就是非葉子節點。
- 度:子節點擁有最多葉子節點的個數。
樹分類
- 一般樹(可以有序)
- 任意一個節點的子節點的個數都不受限制。
- 二叉樹(有序)
- 任意一個節點的子節點的個數最對是兩個,且子節點的位置不可更改。
- 二叉樹分類:
- 一般二叉樹
- 滿二叉樹:在不增加層數的情況下,無法再增加節點。
- 完全二叉樹:如果只是刪除了滿二叉樹最底層最右邊的連續若干個節點,這樣形成的二叉樹就是完全二叉樹。
- 完全二叉樹包含滿二叉樹(滿二叉樹是完全二叉樹的特例)。
- 森林
- n個互不相交的樹的集合。
樹的存儲
- 二叉樹的存儲
- 連續存儲(完全二叉樹)
- 優點:查找某個節點的父節點和子節點(也包括判斷有沒有子節點)速度很快
- 缺點:耗用內存空間過大
- 鏈式存儲
- 連續存儲(完全二叉樹)
- 一般樹的存儲
- 雙親表示法(求父節點方便)
- 孩子表示法(求子節點方便)
- 雙親孩子表示法(求父節點子節點都很方便)
- 二叉樹表示法
- 把一個普通數轉換成二叉樹來存儲。
- 設法保證任意一個節點的左指針域指向它的第一個孩子,右指針域指向它的兄弟節點。
- 一個普通樹轉化成的二叉樹一定沒有右子樹。
- 雙親表示法(求父節點方便)
- 森林的存儲
- 同樣是轉化成二叉樹來存。
- 同樣是轉化成二叉樹來存。
樹的操作(二叉樹)
- 先序遍歷
- 先訪問根節點,再先序訪問左子樹,再先序訪問右子樹。
- 先訪問根節點,再先序訪問左子樹,再先序訪問右子樹。
- 中序遍歷
- 中序遍歷左子樹,再訪問根節點,再中序遍歷右子樹。
- 中序遍歷左子樹,再訪問根節點,再中序遍歷右子樹。
- 後序遍歷
- 中序遍歷左子樹,中序遍歷右子樹,最後訪問根節點。
- 中序遍歷左子樹,中序遍歷右子樹,最後訪問根節點。
- 已知兩種遍歷序列求二叉樹
- 通過先序和中序或者中序和後序,我們可以還原出元素二叉樹(確定唯一二叉樹)。
- 但是通過先序和後序是無法還原原始二叉樹的。
- 已知先序和中序,求後序
- 已知中序和後序,求先序
樹的應用
- 樹是數據庫數據組織的一種重要形式
- 操作系統子父進程的關係就是一棵樹
- 面嚮對象語言中類的繼承關係本身就是一棵樹
- 赫夫曼樹
鏈式二叉樹遍歷具體程序
// 此程序創建一個靜態鏈式二叉樹,並前中後序遍歷
#include<stdio.h>
#include<malloc.h>
struct BTNode{
char data;
struct BTNode * pLchild;// p是指針,L是左
struct BTNode * pRchild;
}
struct BTNode * CreateBTree(void);
void PreTraverseBTree(struct BTNode * pT);
void PostTraverseBTree(struct BTNode * pT);
void InTraverseBTree(struct BTNode * pT);
int main(void){
struct BTNode * pT = CreateBTree();
PreTraverseBTree(pT); // 先序
InTraverseBTree(pT); // 中序
PostTraverseBTree(pT); // 後序
return 0;
}
void PreTraverseBTree(struct BTNode * pT){
if(pT != NULL){ // 條件判斷要加
printf("%c\n",pT->data);
if(NULL != pT){ // 優化
PreTraverseBTree(pT->pLchild);
}
if(NULL != pT){ // 優化
PreTraverseBTree(pT->pRchild);
}
}
}
void PostTraverseBTree(struct BTNode * pT){
if(pT != NULL){ // 條件判斷要加
if(NULL != pT){ // 優化
PreTraverseBTree(pT->pLchild);
}
if(NULL != pT){ // 優化
PreTraverseBTree(pT->pRchild);
}
printf("%c\n",pT->data);
}
}
void InTraverseBTree(struct BTNode * pT){
if(pT != NULL){ // 條件判斷要加
if(NULL != pT){ // 優化
PreTraverseBTree(pT->pLchild);
}
printf("%c\n",pT->data);
if(NULL != pT){ // 優化
PreTraverseBTree(pT->pRchild);
}
}
}
struct BTNode * CreateBTree(void){
struct BTNode * pA = (struct BTNode *)malloc(sizeof(struct BTNode));
struct BTNode * pB = (struct BTNode *)malloc(sizeof(struct BTNode));
struct BTNode * pC = (struct BTNode *)malloc(sizeof(struct BTNode));
struct BTNode * pD = (struct BTNode *)malloc(sizeof(struct BTNode));
struct BTNode * pE = (struct BTNode *)malloc(sizeof(struct BTNode));
pA->data = 'A';
pB->data = 'B';
pC->data = 'C';
pD->data = 'D';
pE->data = 'E';
pA->pLchild = pB;
pA->pRchild = pC;
pB->pLchild = pB->pRchild = NULL;
pC->pLchild = pD;
pC->pRchild = NULL;
pD->pLchild = NULL;
pD->pRchild = pE;
pE->pLchild = pE->pRchild = NULL;
return pA;
}