左子樹鍵值 < 根節點 < 右子樹鍵值。遞歸結構天然適合遞歸操作。
typedef struct TreeNode *Position;
typedef struct TreeNode *SearchTree;
struct TreeNode {
int Element;
SearchTree Left;
SearchTree Right;
};
SearchTree MakeEmpty(SearchTree T) {
if (T != NULL) {
MakeEmpty(T->Left);
MakeEmpty(T->Right);
free(T);
}
return NULL;
}
Position Find(int X, SearchTree T) {
if (T == NULL) return NULL;
if (X < T->Element) return Find(X, T->Left);
else if (X > T->Element) return Find(X, T->Right);
else return T; // 找到
}
Position FindMin(SearchTree T) {
if (T == NULL) return NULL;
else if (T->Left == NULL) return T;
else return FindMin(T->Left); // 一路向左
}
Position FindMax(SearchTree T) {
if (T == NULL) return NULL;
else if (T->Right == NULL) return T;
else return FindMax(T->Right); // 一路向右
}
SearchTree Insert(int X, SearchTree T) {
if (T == NULL) {
T = malloc(sizeof(struct TreeNode));
T->Element = X; T->Left = T->Right = NULL;
} else if (X < T->Element) {
T->Left = Insert(X, T->Left);
} else if (X > T->Element) {
T->Right = Insert(X, T->Right);
}
// 相等不插入
return T;
}
SearchTree Delete(int X, SearchTree T) {
Position TmpCell;
if (T == NULL) {
printf("Element not found\n");
} else if (X < T->Element) {
T->Left = Delete(X, T->Left);
} else if (X > T->Element) {
T->Right = Delete(X, T->Right);
} else { // 找到待刪節點
if (T->Left && T->Right) { // 兩個孩子
// 用右子樹最小節點替代 (或左子樹最大)
TmpCell = FindMin(T->Right);
T->Element = TmpCell->Element;
T->Right = Delete(T->Element, T->Right); // 刪除右子樹中的該最小節點
} else { // 0 或 1 個孩子
TmpCell = T;
if (T->Left == NULL) T = T->Right;
else if (T->Right == NULL) T = T->Left; // 原代碼此處重複判斷 Left==NULL,已修正
free(TmpCell);
}
}
return T;
}
原代碼 Bug 修正:單孩子分支中else if (T->Left == NULL)重複,第二個應為T->Right == NULL(或直接else)。
void ShowTree(SearchTree T) {
if (T != NULL) {
ShowTree(T->Left);
printf("%d ", T->Element);
ShowTree(T->Right);
}
}
int main() {
SearchTree T = NULL;
T = Insert(6, T); T = Insert(2, T); T = Insert(8, T);
T = Insert(1, T); T = Insert(5, T); T = Insert(4, T); T = Insert(3, T);
// 樹結構:
// 6
// / \
// 2 8
// / \
// 1 5
// /
// 4
// /
// 3
Delete(3, T); // 刪除葉子 3
ShowTree(T); // 輸出: 1 2 4 5 6 8
printf("\n");
FindMax(T); // 8
FindMin(T); // 1
MakeEmpty(T); // 釋放內存
return 0;
}
所有操作均遵循“遞歸下行處理子樹,返回值重構父節點鏈接”模式。理解遞歸調用棧的壓入/彈出過程,是掌握樹操作的關鍵。