1.概念
度:
結(jié)點(diǎn)擁有的子樹數(shù)目稱為結(jié)點(diǎn)的度纯出。
結(jié)點(diǎn)的層次:
從根開始定義起,根為第1層是趴,根的子結(jié)點(diǎn)為第2層涛舍,以此類推。
高度或深度:
- 樹中結(jié)點(diǎn)的最大層次唆途。
- 深度從上往下富雅。
- 高度從下往上。
以下不是標(biāo)準(zhǔn)定義肛搬,但對(duì)于我來說很容易記憶没佑。
滿二叉樹:
雙親結(jié)點(diǎn)都有2個(gè)兒子。
完全二叉樹:
- 從根結(jié)點(diǎn)出發(fā)温赔,最深一層以上是滿二叉樹蛤奢。
- 最后一層葉子結(jié)點(diǎn)是從左到右是連續(xù)的,不存在中間有空結(jié)點(diǎn)的情況。
2.實(shí)現(xiàn)
2.1 順序存儲(chǔ)
2.1.1 結(jié)構(gòu)定義
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存儲(chǔ)空間初始分配量 */
#define MAX_TREE_SIZE 100 /* 二叉樹的最大結(jié)點(diǎn)數(shù) */
typedef int Status; /* Status是函數(shù)的類型,其值是函數(shù)結(jié)果狀態(tài)代碼啤贩,如OK等 */
typedef int CElemType; /* 樹結(jié)點(diǎn)的數(shù)據(jù)類型待秃,目前暫定為整型 */
typedef CElemType SqBiTree[MAX_TREE_SIZE]; /* 0號(hào)單元存儲(chǔ)根結(jié)點(diǎn) */
CElemType Nil = 0; /*設(shè)整型以0為空 或者以 INT_MAX(65535)*/
// 左兒子索引(雙親結(jié)點(diǎn)出發(fā))
#define LeftChild(x) (x)*2+1
// 雙親索引(左兒子反過來算)
// 右兒子多的1,除以2后為0痹屹,沒有影響
// 如果要記锥余,就記左兒子算法,雙親直接反推
#define Parent(x) ((x)-1)/2
// 查找用
typedef struct {
int level; //結(jié)點(diǎn)層
int order; //本層的序號(hào)(按照滿二叉樹給定序號(hào)規(guī)則)
} Position;
2.1.2 基礎(chǔ)操作
// 1.訪問
Status visit(CElemType c){
printf("%d ", c);
return OK;
}
// 2.構(gòu)造空二叉樹
Status InitBiTree(SqBiTree T) {
memset(T, Nil, MAX_TREE_SIZE-1);
// for (int i = 0; i < MAX_TREE_SIZE; i++) {
// //將二叉樹初始化值置空
// T[i] = Nil;
// }
return OK;
}
// 3.按層序次序輸入二叉樹中的結(jié)點(diǎn)值(字符型或整型)痢掠,構(gòu)造順序存儲(chǔ)的二叉樹T
Status CreateBiTree(SqBiTree T) {
/*
1 -->1
2 3 -->2
4 5 6 7 -->3
8 9 10 -->4
1 2 3 4 5 6 7 8 9 10 Nil Nil Nil
*/
int i = 0;
while (i < 10) {
T[i] = i+1;
printf("%d ",T[i]);
//結(jié)點(diǎn)不為空,且無雙親結(jié)點(diǎn)
if (i != 0 // 不是根結(jié)點(diǎn)需要判斷雙親
&& T[i] != Nil // 結(jié)點(diǎn)不為空嘲恍,如果雙親結(jié)點(diǎn)為空就有問題
&& T[Parent(i)] == Nil) { // 雙親結(jié)點(diǎn)為空
printf("出現(xiàn)無雙親的非根結(jié)點(diǎn)%d\n",T[i]);
T[i] = Nil;
return ERROR;
// 或者直接退出
// exit(ERROR);
}
i++;
}
printf("\n");
//將空賦值給T的后面的結(jié)點(diǎn)
while (i < MAX_TREE_SIZE) {
T[i] = Nil;
i++;
}
return OK;
}
// 4.清空二叉樹
// 兩個(gè)函數(shù)完全一樣足画,沒必要寫2份,但是為了閱讀方便可以重命名
#define ClearBiTree InitBiTree
// 5.判斷二叉樹是否為空
Status BiTreeEmpty(SqBiTree T) {
//根結(jié)點(diǎn)為空佃牛,則二叉樹為空
if (T[0] == Nil)
return TRUE;
return FALSE;
}
// 6.獲取二叉樹的深度
int BiTreeDepth(SqBiTree T) {
int i = MAX_TREE_SIZE - 1, j = 0;
for (; i>=0 && T[i] == Nil; i--);// 最后一個(gè)葉子節(jié)點(diǎn)
// 左斜樹序號(hào) 1 2 4 8 ...
// 索引需要-1淹辞,0 1 3 7 ...,所以是powl(2, j)-1
// j層的頭序號(hào)比最后一個(gè)葉子節(jié)點(diǎn)大時(shí)停止遍歷
for (; powl(2, j)-1 <= i; j++);
return j;
}
// 7.返回處于位置e(層,本層序號(hào))的結(jié)點(diǎn)值
CElemType Value(SqBiTree T, Position e){
/*
Position.level -> 結(jié)點(diǎn)層.表示第幾層;
Position.order -> 本層的序號(hào)(按照滿二叉樹給定序號(hào)規(guī)則)
*/
// 深度為層數(shù)-1
int depth = e.level - 1;
// 左斜樹序號(hào) 1 2 4 8 ...
// 索引需要-1俘侠,0 1 3 7 ...象缀,所以是powl(2, depth)-1
int levelStart = (int)pow(2, depth) - 1;
// order從1開始而不是0,所以-1
int idx = e.order - 1;
return T[levelStart + idx];
}
// 8.獲取二叉樹跟結(jié)點(diǎn)的值
Status Root(SqBiTree T,CElemType *e){
if (T[0] == Nil) return ERROR;
*e = T[0];
return OK;
}
// 9.給處于位置e的結(jié)點(diǎn)賦值
Status Assign(SqBiTree T, Position e, CElemType value) {
// 深度為層數(shù)-1
int depth = e.level - 1;
// 左斜樹序號(hào) 1 2 4 8 ...
// 索引需要-1爷速,0 1 3 7 ...央星,所以是powl(2, depth)-1
int levelStart = (int)pow(2, depth) - 1;
// order從1開始而不是0,所以-1
int idx = e.order - 1;
// 目標(biāo)位置
int i = levelStart + idx;
// 重點(diǎn)1:葉子結(jié)點(diǎn)的雙親為空
if (value != Nil && T[Parent(i)] == Nil) return ERROR;
// 重點(diǎn)2:給雙親賦空值但是有葉子結(jié)點(diǎn)
if (value == Nil && (T[LeftChild(i)] != Nil || T[LeftChild(i)+1] != Nil)) return ERROR;
// 成功賦值
T[i] = value;
return OK;
}
// 10.獲取e的雙親
CElemType ParentValue(SqBiTree T, CElemType e) {
if (T[0] == Nil) return Nil; //空樹
for (int i = 1 ; i < MAX_TREE_SIZE; i++) {
if (T[i] == e) {
return T[Parent(i)]; //找到e
}
}
return Nil; //沒有找到
}
// 11.獲取某個(gè)結(jié)點(diǎn)的左孩子
CElemType LeftChildValue(SqBiTree T, CElemType e) {
if (T[0] == Nil) return Nil; //空樹
for (int i = 0 ; i < MAX_TREE_SIZE-1; i++) {
if (T[i] == e) { //找到e
return T[LeftChild(i)];
}
}
return Nil; //沒有找到
}
// 12.獲取某個(gè)結(jié)點(diǎn)的右孩子
CElemType RightChild(SqBiTree T,CElemType e){
if (T[0] == Nil) return Nil; //空樹
for (int i = 0 ; i < MAX_TREE_SIZE-1; i++) {
if (T[i] == e) { //找到e
return T[LeftChild(i)+1];
}
}
return Nil; //沒有找到
}
// 13.獲取結(jié)點(diǎn)的左兄弟惫东,e值必須是右孩子才有左兄弟
CElemType LeftSibling(SqBiTree T, CElemType e) {
if (T[0] == Nil) return Nil; //空樹
for (int i=1; i <= MAX_TREE_SIZE-1; i++) // 頭結(jié)點(diǎn)沒有左兄弟莉给,從1開始
if (T[i]==e && i%2==0) return T[i-1]; // 找到e且其序號(hào)為偶數(shù)(是右孩子)
return Nil; //沒有找到
}
// 14.獲取結(jié)點(diǎn)的右兄弟,e值必須是左孩子才有右兄弟
CElemType RightSibling(SqBiTree T, CElemType e) {
if (T[0] == Nil) return Nil; //空樹
for (int i=1; i <= MAX_TREE_SIZE-1; i++) // 頭結(jié)點(diǎn)沒有左兄弟廉沮,從1開始
if (T[i]==e && i%2==1) return T[i+1]; // 找到e且其序號(hào)為奇數(shù)(是左孩子)
return Nil; //沒有找到
}
2.1.3 遍歷
// 1.層序遍歷(存儲(chǔ)就是層序的)
void LevelOrderTraverse(SqBiTree T){
int i = MAX_TREE_SIZE - 1;
for (; i>=0 && T[i] == Nil; i--);// 最后一個(gè)葉子結(jié)點(diǎn)
for (int j = 0; j <= i; j++) //從根結(jié)點(diǎn)起颓遏,按層序遍歷二叉樹
if (T[j] != Nil) //只遍歷非空結(jié)點(diǎn)
visit(T[j]);
printf("\n");
}
// 2.前序遍歷二叉樹
void PreTraverse(SqBiTree T, int i){
//打印結(jié)點(diǎn)數(shù)據(jù)
visit(T[i]);
//遍歷左子樹
if (T[LeftChild(i)] != Nil) PreTraverse(T, LeftChild(i));
//遍歷右子樹
if (T[LeftChild(i)+1] != Nil) PreTraverse(T, LeftChild(i)+1);
}
Status PreOrderTraverse(SqBiTree T) {
if (T[0] != Nil) //樹不為空
PreTraverse(T, 0); // 遞歸遍歷
printf("\n");
return OK;
}
// 3.中序遍歷二叉樹
void InTraverse(SqBiTree T, int i) {
//遍歷左子樹
if (T[LeftChild(i)] != Nil) InTraverse(T, LeftChild(i));
//打印結(jié)點(diǎn)數(shù)據(jù)
visit(T[i]);
//遍歷右子樹
if (T[LeftChild(i)+1] != Nil) InTraverse(T, LeftChild(i)+1);
}
Status InOrderTraverse(SqBiTree T) {
if (T[0] != Nil) //樹不為空
InTraverse(T, 0); // 遞歸遍歷
printf("\n");
return OK;
}
// 4.后序遍歷
void PostTraverse(SqBiTree T,int i) {
//遍歷左子樹
if (T[LeftChild(i)] != Nil) PostTraverse(T, LeftChild(i));
//遍歷右子樹
if (T[LeftChild(i)+1] != Nil) PostTraverse(T, LeftChild(i)+1);
//打印結(jié)點(diǎn)數(shù)據(jù)
visit(T[i]);
}
Status PostOrderTraverse(SqBiTree T) {
if (T[0] != Nil) //樹不為空
PostTraverse(T,0);
printf("\n");
return OK;
}
2.1.4 檢驗(yàn)
int main(int argc, const char * argv[]) {
printf("二叉樹順序存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn)!\n");
Status iStatus;
Position p;
CElemType e;
SqBiTree T;
/*
1 -->1
2 3 -->2
4 5 6 7 -->3
8 9 10 -->4
1 2 3 4 5 6 7 8 9 10 Nil Nil Nil
*/
InitBiTree(T);
CreateBiTree(T);
printf("建立二叉樹后,樹空否滞时?%d (1:是 0:否) \n",BiTreeEmpty(T));
printf("樹的深度 = %d\n",BiTreeDepth(T));
p.level = 3;
p.order = 2;
e = Value(T, p);
printf("第%d層第%d個(gè)結(jié)點(diǎn)的值: %d\n",p.level,p.order,e);
iStatus = Root(T, &e);
if (iStatus) {
printf("二叉樹的根為:%d\n",e);
} else {
printf("樹為空,無根!\n");
}
//向樹中3層第2個(gè)結(jié)點(diǎn)位置上結(jié)點(diǎn)賦值99
e = 99;
Assign(T, p, e);
//獲取樹中3層第2個(gè)結(jié)點(diǎn)位置結(jié)點(diǎn)的值是多少:
e = Value(T,p);
printf("第%d層第%d個(gè)結(jié)點(diǎn)的值: %d\n",p.level,p.order,e);
//找到e這個(gè)結(jié)點(diǎn)的雙親;
printf("結(jié)點(diǎn)%d的雙親為: %d ", e, ParentValue(T, e));
//找到e這個(gè)結(jié)點(diǎn)的左右孩子;
printf("左右孩子分別為: %d, %d\n", LeftChildValue(T, e), RightChild(T, e));
//找到e這個(gè)結(jié)點(diǎn)的左右兄弟;
printf("結(jié)點(diǎn)%d的左右兄弟: %d, %d\n", e, LeftSibling(T, e), RightSibling(T, e));
// 還原
Assign(T, p, 5);
// 開始遍歷
printf("二叉樹T層序遍歷:");
LevelOrderTraverse(T);
printf("二叉樹T先序遍歷:");
PreOrderTraverse(T);
printf("二叉樹T中序遍歷:");
InOrderTraverse(T);
printf("二叉樹T后序遍歷:");
PostOrderTraverse(T);
return 0;
}
// 輸出
二叉樹順序存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn)!
1 2 3 4 5 6 7 8 9 10
建立二叉樹后叁幢,樹空否?0 (1:是 0:否)
樹的深度 = 4
第3層第2個(gè)結(jié)點(diǎn)的值: 5
二叉樹的根為:1
第3層第2個(gè)結(jié)點(diǎn)的值: 99
結(jié)點(diǎn)99的雙親為: 2 左右孩子分別為: 10, 0
結(jié)點(diǎn)99的左右兄弟: 4, 0
二叉樹T層序遍歷:1 2 3 4 5 6 7 8 9 10
二叉樹T先序遍歷:1 2 4 8 9 5 10 3 6 7
二叉樹T中序遍歷:8 4 9 2 10 5 1 6 3 7
二叉樹T后序遍歷:8 9 4 10 5 2 6 7 3 1
2.2 鏈?zhǔn)酱鎯?chǔ)
2.2.1 結(jié)構(gòu)定義
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
/* Status是函數(shù)的類型,其值是函數(shù)結(jié)果狀態(tài)代碼坪稽,如OK等 */
typedef int Status;
// 數(shù)據(jù)結(jié)構(gòu)
typedef char CElemType;
CElemType Nil = '#'; /* 以#為空 */
typedef struct BiTNode { /* 結(jié)點(diǎn)結(jié)構(gòu) */
CElemType data; /* 結(jié)點(diǎn)數(shù)據(jù) */
struct BiTNode *lchild, *rchild; /* 左右孩子指針 */
} BiTNode, *BiTree;
為了方便后續(xù)創(chuàng)建二叉樹:
// 全局變量
#define MAXSIZE 100 //存儲(chǔ)空間初始分配量
typedef char String[MAXSIZE]; /* 0號(hào)單元存放串的長度 */
String str;
Status StrAssign(String T, char *chars) {
size_t length = strlen(chars);
if (length > MAXSIZE) return ERROR;
T[0] = length;
for (int i = 1; i <= T[0]; i++)
T[i] = *(chars+i-1);
return OK;
}
2.2.2 基礎(chǔ)操作
// 1.打印數(shù)據(jù)
Status visit(CElemType e) {
printf("%c ",e);
return OK;
}
// 2.構(gòu)造空二叉樹T
Status InitBiTree(BiTree *T) {
*T = NULL;
return OK;
}
// 3.銷毀二叉樹
void DestroyBiTree(BiTree *T) {
if (*T) {
// 有左孩子
if ((*T)->lchild)
DestroyBiTree(&(*T)->lchild); // 銷毀左孩子子樹
// 有右孩子
if ((*T)->rchild)
DestroyBiTree(&(*T)->rchild); // 銷毀右孩子子樹
free(*T); // 釋放結(jié)點(diǎn)
*T = NULL; // 指針賦空
}
}
// 4.清空樹和銷毀代碼完全一樣
#define ClearBiTree DestroyBiTree
// 5.創(chuàng)建二叉樹
int createIndex = 1;
void CreateBiTree(BiTree *T) {
CElemType ch = str[createIndex++]; // 獲取字符
if (ch == Nil) { // 判斷當(dāng)前字符是否為空
*T = NULL;
} else {
//創(chuàng)建新的結(jié)點(diǎn)
*T = (BiTree)malloc(sizeof(BiTNode));
//是否創(chuàng)建成功
if (!*T) {
exit(OVERFLOW);
}
(*T)->data = ch; // 生成根結(jié)點(diǎn)
CreateBiTree(&(*T)->lchild); // 構(gòu)造左子樹
CreateBiTree(&(*T)->rchild); // 構(gòu)造右子樹
}
}
// 6.二叉樹T是否為空
Status BiTreeEmpty(BiTree T) {
if (T)
return FALSE;
else
return TRUE;
}
// 7.二叉樹T的深度
int BiTreeDepth(BiTree T) {
if (!T) return 0;
int i, j;
i = T->lchild ? BiTreeDepth(T->lchild) : 0; // 計(jì)算左孩子的深度
j = T->rchild ? BiTreeDepth(T->rchild) : 0; // 計(jì)算右孩子的深度
return i > j ? i+1 : j+1; // 比較i和j
}
// 8.二叉樹T的根
CElemType Root(BiTree T) {
if (BiTreeEmpty(T)) return Nil;
return T->data;
}
// 9.返回p所指向的結(jié)點(diǎn)值
CElemType Value(BiTree p) {
return p->data;
}
// 10.給p所指結(jié)點(diǎn)賦值為value
void Assign(BiTree p, CElemType value) {
p->data = value;
}
2.2.3 遍歷
// 1.前序遞歸遍歷T
void PreOrderTraverse(BiTree T) {
if (!T) return;
printf("%c", T->data); // 顯示結(jié)點(diǎn)數(shù)據(jù)
PreOrderTraverse(T->lchild); // 遍歷左子樹
PreOrderTraverse(T->rchild); // 遍歷右子樹
}
// 2.中序遞歸遍歷T
void InOrderTraverse(BiTree T) {
if (!T) return;
InOrderTraverse(T->lchild); // 遍歷左子樹
printf("%c", T->data); // 顯示結(jié)點(diǎn)數(shù)據(jù)
InOrderTraverse(T->rchild); // 遍歷右子樹
}
// 3.后序遞歸遍歷T
void PostOrderTraverse(BiTree T) {
if (!T) return;
PostOrderTraverse(T->lchild); // 遍歷左子樹
PostOrderTraverse(T->rchild); // 遍歷右子樹
printf("%c", T->data); // 顯示結(jié)點(diǎn)數(shù)據(jù)
}
2.2.4 檢驗(yàn)
int main(int argc, const char * argv[]) {
printf("二叉樹鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)實(shí)現(xiàn)!\n");
BiTree T;
CElemType e1;
/*
A
B C
D E F G
H # # # I # # J
# K # # # #
# #
ABDH#K###E##CFI###G#J##
*/
InitBiTree(&T);
StrAssign(str,"ABDH#K###E##CFI###G#J##");
CreateBiTree(&T);
printf("二叉樹是否為空: %d (1:是 0:否)\n樹的深度: %d\n", BiTreeEmpty(T), BiTreeDepth(T));
e1 = Root(T);
printf("二叉樹的根為: %c\n",e1);
printf("前序遍歷二叉樹:");
PreOrderTraverse(T);
printf("\n中序遍歷二叉樹:");
InOrderTraverse(T);
printf("\n后序遍歷二叉樹:");
PostOrderTraverse(T);
printf("\n");
return 0;
}
// 輸出
二叉樹鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)實(shí)現(xiàn)!
二叉樹是否為空: 0 (1:是 0:否)
樹的深度: 5
二叉樹的根為: A
前序遍歷二叉樹:ABDHKECFIGJ
中序遍歷二叉樹:HKDBEAIFCGJ
后序遍歷二叉樹:KHDEBIFJGCA
2.2.5 非遞歸遍歷
// 1.前序循環(huán)遍歷T
void LoopPreOrderTraverse(BiTree T) {
if (!T) return;
// 這里偷懶知道樹高5
int top = -1;
BiTNode **stack = (BiTNode **)malloc(sizeof(BiTNode*) * 5);
BiTNode *cur = T;
while (cur || top > -1){
while (cur) {
stack[++top] = cur;
printf("%c", cur->data); // 顯示結(jié)點(diǎn)數(shù)據(jù)
cur = cur->lchild;
}
if (top > -1) {
cur = stack[top];
--top;
cur = cur->rchild;
}
}
free(stack);
}
// 2.前序循環(huán)遍歷T
void LoopInOrderTraverse(BiTree T) {
if (!T) return;
// 這里偷懶知道樹高5
int top = -1;
BiTNode **stack = (BiTNode **)malloc(sizeof(BiTNode*) * 5);
BiTNode *cur = T;
while (cur || top > -1){
while (cur) {
stack[++top] = cur;
cur = cur->lchild;
}
if (top > -1) {
cur = stack[top];
printf("%c", cur->data); // 顯示結(jié)點(diǎn)數(shù)據(jù)
--top;
cur = cur->rchild;
}
}
free(stack);
}
// 3.前序循環(huán)遍歷T
void LoopPostOrderTraverse(BiTree T) {
if (!T) return;
// 這里偷懶知道樹高5
int top = -1;
BiTNode **stack = (BiTNode **)malloc(sizeof(BiTNode*) * 5);
BiTNode *cur = T, *recent = NULL;
while (cur || top > -1) {
if (cur) { //走到最左邊
stack[++top] = cur;
cur = cur->lchild;
} else {
cur = stack[top];
if (cur->rchild && cur->rchild != recent) //右子樹存在,未被訪問
cur = cur->rchild;
else {
--top;
printf("%c", cur->data); // 顯示結(jié)點(diǎn)數(shù)據(jù)
recent = cur; //記錄最近訪問過的節(jié)點(diǎn)
cur = NULL; //節(jié)點(diǎn)訪問完后演训,重置p指針
}
}
}
free(stack);
}
// 檢驗(yàn)
int main(int argc, const char * argv[]) {
BiTree T;
CElemType e1;
/*
A
B C
D E F G
H # # # I # # J
# K # # # #
# #
ABDH#K###E##CFI###G#J##
*/
InitBiTree(&T);
StrAssign(str,"ABDH#K###E##CFI###G#J##");
CreateBiTree(&T);
printf("遞歸前序遍歷二叉樹:");
PreOrderTraverse(T);
printf("\n遞歸中序遍歷二叉樹:");
InOrderTraverse(T);
printf("\n遞歸后序遍歷二叉樹:");
PostOrderTraverse(T);
printf("\n循環(huán)前序遍歷二叉樹:");
LoopPreOrderTraverse(T);
printf("\n循環(huán)中序遍歷二叉樹:");
LoopInOrderTraverse(T);
printf("\n循環(huán)后序遍歷二叉樹:");
LoopPostOrderTraverse(T);
printf("\n");
return 0;
}
// 輸出
遞歸前序遍歷二叉樹:ABDHKECFIGJ
遞歸中序遍歷二叉樹:HKDBEAIFCGJ
遞歸后序遍歷二叉樹:KHDEBIFJGCA
循環(huán)前序遍歷二叉樹:ABDHKECFIGJ
循環(huán)中序遍歷二叉樹:HKDBEAIFCGJ
循環(huán)后序遍歷二叉樹:KHDEBIFJGCA