4-2. 二叉搜索树 (BST)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>// 二叉树节点结构定义
typedef struct BiTNode {char data; // 数据域struct BiTNode *lchild; // 左孩子指针struct BiTNode *rchild; // 右孩子指针
} BiTNode;// 二叉树类型的定义
typedef BiTNode *BiTree;/*-------------------------链栈结构定义,用于非递归遍历------------------------*/// 栈节点结构定义
typedef struct StackNode {BiTree data_ptr; // 数据域: 存储二叉树节点指针struct StackNode *next;
} StackNode;// 链栈结构
typedef struct LinkedStack {StackNode *top; // 栈顶指针int length; // 节点个数
} LinkedStack;/*** 初始化栈* 时间复杂度: O(1)* 空间复杂度: O(1)*/
void InitStack(LinkedStack *stack) {if (stack == NULL) return;stack->top = NULL;stack->length = 0;
}/*** 判断栈是否为空* 时间复杂度: O(1)* 空间复杂度: O(1)*/
bool StackIsEmpty(LinkedStack *stack) {if (stack == NULL) return true;return stack->top == NULL;
}/*** 入栈操作* 时间复杂度: O(1)* 空间复杂度: O(1)*/
bool Push(LinkedStack *stack, BiTree treeNode) {if (stack == NULL || treeNode == NULL) return false;StackNode *newNode = (StackNode *) malloc(sizeof(StackNode));if (!newNode) return false;newNode->data_ptr = treeNode;newNode->next = stack->top;stack->top = newNode;stack->length++;return true;
}/*** 出栈操作* 时间复杂度: O(1)* 空间复杂度: O(1)*/
bool Pop(LinkedStack *stack, BiTree *treeNode) {if (StackIsEmpty(stack)) return false;StackNode *tmp = stack->top;*treeNode = tmp->data_ptr;stack->top = tmp->next;stack->length--;free(tmp);return true;
}/*** 获取栈顶元素* 时间复杂度: O(1)* 空间复杂度: O(1)*/
BiTree GetTop(LinkedStack *stack) {if (StackIsEmpty(stack)) return NULL;return stack->top->data_ptr;
}/*-------------------------队列结构定义,用于层次遍历------------------------*/typedef struct QueueNode {BiTree data_ptr; // 数据域:存储二叉树节点指针struct QueueNode *next;
} QueueNode;typedef struct LinkedQueue {QueueNode *front; // 队头指针QueueNode *rear; // 队尾指针int length; // 队列长度
} LinkedQueue;/*** 初始化队列* 时间复杂度: O(1)* 空间复杂度: O(1)*/
void InitQueue(LinkedQueue *queue) {if (queue == NULL) return;queue->front = NULL;queue->rear = NULL;queue->length = 0;
}/*** 判断队列是否为空* 时间复杂度: O(1)* 空间复杂度: O(1)*/
bool QueueIsEmpty(LinkedQueue *queue) {if (queue == NULL) return true;return queue->front == NULL;
}/*** 入队操作* 时间复杂度: O(1)* 空间复杂度: O(1)*/
bool Enqueue(LinkedQueue *queue, BiTree treeNode) {if (queue == NULL || treeNode == NULL) return false;QueueNode *newNode = (QueueNode *) malloc(sizeof(QueueNode));if (!newNode) return false;newNode->data_ptr = treeNode;newNode->next = NULL;if (QueueIsEmpty(queue)) {queue->front = newNode;queue->rear = newNode;} else {queue->rear->next = newNode;queue->rear = newNode;}queue->length++;return true;
}/*** 出队操作* 时间复杂度: O(1)* 空间复杂度: O(1)*/
bool DeQueue(LinkedQueue *queue, BiTree *treeNode) {if (QueueIsEmpty(queue)) return false;QueueNode *tmp = queue->front;*treeNode = tmp->data_ptr;queue->front = tmp->next;queue->length--;if (queue->front == NULL) queue->rear = NULL;free(tmp);return true;
}/*-------------------------二叉搜索树操作函数------------------------*//*** 初始化二叉树* 时间复杂度: O(1)* 空间复杂度: O(1)*/
void InitBiTree(BiTree *tree) {if (tree == NULL) return;*tree = NULL;
}/*** 二叉搜索树插入节点(递归)* 时间复杂度:* - 平均情况: O(log n), 其中n为节点个数* - 最坏情况: O(n), 当树退化为链表时* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
bool BST_Insert(BiTree *tree, char key) {if (tree == NULL) return false;if (*tree == NULL) {*tree = (BiTNode *)malloc(sizeof(BiTNode));if (!*tree) return false;(*tree)->data = key;(*tree)->lchild = (*tree)->rchild = NULL;return true;}if (key < (*tree)->data) {return BST_Insert(&(*tree)->lchild, key);} else if (key > (*tree)->data) {return BST_Insert(&(*tree)->rchild, key);} else {return false; // 键值已存在}
}/*** 二叉搜索树插入节点(非递归)* 时间复杂度:* - 平均情况: O(log n), 其中n为节点个数* - 最坏情况: O(n), 当树退化为链表时* 空间复杂度: O(1)*/
bool BST_Insert_NonRecursive(BiTree *tree, char key) {if (tree == NULL) return false;BiTNode *newNode = (BiTNode *)malloc(sizeof(BiTNode));if (!newNode) return false;newNode->data = key;newNode->lchild = newNode->rchild = NULL;if (*tree == NULL) {*tree = newNode;return true;}BiTNode *current = *tree;BiTNode *parent = NULL;while (current != NULL) {parent = current;if (key < current->data) {current = current->lchild;} else if (key > current->data) {current = current->rchild;} else {free(newNode);return false;}}if (key < parent->data) {parent->lchild = newNode;} else {parent->rchild = newNode;}return true;
}/*** 二叉搜索树查找(递归)* 时间复杂度:* - 平均情况: O(log n), 其中n为节点个数* - 最坏情况: O(n), 当树退化为链表时* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
BiTNode* BST_Search(BiTree tree, char key) {if (tree == NULL) return NULL;if (key == tree->data) {return tree;} else if (key < tree->data) {return BST_Search(tree->lchild, key);} else {return BST_Search(tree->rchild, key);}
}/*** 二叉搜索树查找(非递归)* 时间复杂度:* - 平均情况: O(log n), 其中n为节点个数* - 最坏情况: O(n), 当树退化为链表时* 空间复杂度: O(1)*/
BiTNode* BST_Search_NonRecursive(BiTree tree, char key) {BiTNode *current = tree;while (current != NULL) {if (key == current->data) {return current;} else if (key < current->data) {current = current->lchild;} else {current = current->rchild;}}return NULL;
}/*** 查找二叉搜索树的最小值节点* 时间复杂度:* - 平均情况: O(log n), 其中n为节点个数* - 最坏情况: O(n), 当树退化为链表时* 空间复杂度: O(1)*/
BiTNode* BST_FindMin(BiTree tree) {if (tree == NULL) return NULL;BiTNode *current = tree;while (current->lchild != NULL) {current = current->lchild;}return current;
}/*** 查找二叉搜索树的最大值节点* 时间复杂度:* - 平均情况: O(log n), 其中n为节点个数* - 最坏情况: O(n), 当树退化为链表时* 空间复杂度: O(1)*/
BiTNode* BST_FindMax(BiTree tree) {if (tree == NULL) return NULL;BiTNode *current = tree;while (current->rchild != NULL) {current = current->rchild;}return current;
}/*** 二叉搜索树删除节点(递归)* 时间复杂度:* - 平均情况: O(log n), 其中n为节点个数* - 最坏情况: O(n), 当树退化为链表时* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
bool BST_Delete(BiTree *tree, char key) {if (tree == NULL || *tree == NULL) return false;if (key < (*tree)->data) {return BST_Delete(&(*tree)->lchild, key);} else if (key > (*tree)->data) {return BST_Delete(&(*tree)->rchild, key);} else {BiTNode *temp = *tree;if ((*tree)->lchild == NULL) {*tree = (*tree)->rchild;free(temp);} else if ((*tree)->rchild == NULL) {*tree = (*tree)->lchild;free(temp);} else {BiTNode *minNode = BST_FindMin((*tree)->rchild);(*tree)->data = minNode->data;BST_Delete(&(*tree)->rchild, minNode->data);}return true;}
}/*** 判断是否为二叉搜索树* 时间复杂度: O(n), 其中n为节点个数(需要遍历所有节点)* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
bool IsBST(BiTree tree) {static BiTNode *prev = NULL;if (tree == NULL) return true;if (!IsBST(tree->lchild)) return false;if (prev != NULL && tree->data <= prev->data) return false;prev = tree;return IsBST(tree->rchild);
}/*** 创建二叉搜索树(通过插入多个元素)* 时间复杂度: O(n log n), 其中n为keys数组长度* - 平均情况: 每次插入O(log n),共n次* - 最坏情况: O(n²), 当插入有序序列导致树退化为链表时* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
void CreateBST(BiTree *tree, char keys[], int n) {if (tree == NULL || keys == NULL) return;InitBiTree(tree);for (int i = 0; i < n; i++) {BST_Insert(tree, keys[i]);}
}/*** 中序遍历(递归)- 用于验证BST的有序性* 时间复杂度: O(n), 其中n为节点个数(需要遍历所有节点)* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
void InOrderTraverse(BiTree tree) {if (tree) {InOrderTraverse(tree->lchild);printf("%c ", tree->data);InOrderTraverse(tree->rchild);}
}/*** 层次遍历* 时间复杂度: O(n), 其中n为节点个数(需要遍历所有节点)* 空间复杂度: O(w), 其中w为树的最大宽度(队列中最多同时存储一层的节点)*/
void LevelOrderTraverse(BiTree tree) {if (tree == NULL) return;LinkedQueue queue;InitQueue(&queue);BiTNode *current = tree;Enqueue(&queue, current);while (!QueueIsEmpty(&queue)) {DeQueue(&queue, ¤t);printf("%c ", current->data);if (current->lchild != NULL) Enqueue(&queue, current->lchild);if (current->rchild != NULL) Enqueue(&queue, current->rchild);}printf("\n");
}/*** 计算二叉树深度* 时间复杂度: O(n), 其中n为节点个数(需要遍历所有节点)* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
int BiTreeDepth(BiTree tree) {if (tree == NULL) return 0;int leftDepth = BiTreeDepth(tree->lchild);int rightDepth = BiTreeDepth(tree->rchild);return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;
}/*** 统计节点个数* 时间复杂度: O(n), 其中n为节点个数(需要遍历所有节点)* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
int NodeCount(BiTree tree) {if (tree == NULL) return 0;return NodeCount(tree->lchild) + NodeCount(tree->rchild) + 1;
}/*** 统计叶子节点个数* 时间复杂度: O(n), 其中n为节点个数(需要遍历所有节点)* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
int LeafCount(BiTree tree) {if (tree == NULL) return 0;if (tree->lchild == NULL && tree->rchild == NULL) return 1;return LeafCount(tree->lchild) + LeafCount(tree->rchild);
}/*** 销毁二叉树* 时间复杂度: O(n), 其中n为节点个数(需要遍历所有节点)* 空间复杂度:* - 平均情况: O(log n), 递归栈深度* - 最坏情况: O(n), 当树退化为链表时*/
void DestroyBiTree(BiTree *tree) {if (tree == NULL || *tree == NULL) return;DestroyBiTree(&(*tree)->lchild);DestroyBiTree(&(*tree)->rchild);free(*tree);*tree = NULL;
}/*-------------------------测试函数------------------------*/int main() {printf("=== 二叉搜索树(BST)完整测试 ===\n\n");BiTree bst;InitBiTree(&bst);// 测试数据char keys[] = {'D', 'B', 'F', 'A', 'C', 'E', 'G'};int n = sizeof(keys) / sizeof(keys[0]);printf("1. 创建二叉搜索树\n");printf(" 插入序列: ");for (int i = 0; i < n; i++) {printf("%c ", keys[i]);}printf("\n");CreateBST(&bst, keys, n);printf("\n2. 遍历验证\n");printf(" 中序遍历: ");InOrderTraverse(bst);printf("\n");printf(" 层次遍历: ");LevelOrderTraverse(bst);printf("\n3. 搜索测试\n");char testKeys[] = {'C', 'X', 'A', 'Z'};for (int i = 0; i < 4; i++) {BiTNode *result = BST_Search(bst, testKeys[i]);if (result) {printf(" 找到节点: %c\n", testKeys[i]);} else {printf(" 未找到节点: %c\n", testKeys[i]);}}printf("\n4. 最值测试\n");BiTNode *minNode = BST_FindMin(bst);BiTNode *maxNode = BST_FindMax(bst);printf(" 最小值: %c\n", minNode->data);printf(" 最大值: %c\n", maxNode->data);printf("\n5. 删除操作测试\n");printf(" 删除前中序遍历: ");InOrderTraverse(bst);printf("\n");printf(" 删除节点 'B'\n");BST_Delete(&bst, 'B');printf(" 删除后中序遍历: ");InOrderTraverse(bst);printf("\n");printf("\n6. BST属性验证\n");if (IsBST(bst)) {printf(" 这是一棵二叉搜索树!\n");} else {printf(" 这不是二叉搜索树!\n");}printf("\n7. 树属性统计\n");printf(" 树深度: %d\n", BiTreeDepth(bst));printf(" 节点总数: %d\n", NodeCount(bst));printf(" 叶子节点数: %d\n", LeafCount(bst));printf("\n8. 非递归操作测试\n");printf(" 插入节点'H'\n");BST_Insert_NonRecursive(&bst, 'H');printf(" 插入后中序遍历: ");InOrderTraverse(bst);printf("\n");printf(" 非递归查找 'E': ");BiTNode *nonRecResult = BST_Search_NonRecursive(bst, 'E');if (nonRecResult) {printf("找到!\n");} else {printf("未找到!\n");}printf("\n9. 内存清理\n");DestroyBiTree(&bst);printf(" 二叉搜索树已销毁!\n");return 0;
}
运行结果
=== 二叉搜索树(BST)完整测试 ===1. 创建二叉搜索树插入序列: D B F A C E G2. 遍历验证中序遍历: A B C D E F G层次遍历: D B F A C E G3. 搜索测试找到节点: C未找到节点: X找到节点: A未找到节点: Z4. 最值测试最小值: A最大值: G5. 删除操作测试删除前中序遍历: A B C D E F G删除节点 'B'删除后中序遍历: A C D E F G6. BST属性验证这是一棵二叉搜索树!7. 树属性统计树深度: 3节点总数: 6叶子节点数: 38. 非递归操作测试插入节点'H'插入后中序遍历: A C D E F G H非递归查找 'E': 找到!9. 内存清理二叉搜索树已销毁!
二叉搜索树 (BST) 相关知识点
1. 基础概念
二叉搜索树定义:
- 左子树所有节点值 < 根节点值
- 右子树所有节点值 > 根节点值
- 左右子树也都是BST
重要性质:
- 中序遍历结果为有序序列
- 查找、插入、删除的平均时间复杂度:O(log n)
- 最坏情况(退化为链表)时间复杂度:O(n)
时间复杂度分析
操作 | 平均情况 | 最坏情况 | 空间复杂度 |
---|---|---|---|
查找 | O(log n) | O(n) | O(1)非递归 / O(h)递归 |
插入 | O(log n) | O(n) | O(1)非递归 / O(h)递归 |
删除 | O(log n) | O(n) | O(h) |
中序遍历 | O(n) | O(n) | O(h) |
2. 常见题型及解析
题型1: BST基本操作实现
解答模版:
/*** BST节点插入(递归)* 时间复杂度: 平均O(log n), 最坏O(n)* 空间复杂度: 平均O(log n), 最坏O(n)*/
bool BST_Insert(BiTree *T, int key) {if (T == NULL) return false;if (*T == NULL) {*T = (BSTNode*)malloc(sizeof(BSTNode));(*T)->data = key;(*T)->lchild = (*T)->rchild = NULL;return true;}if (key < (*T)->data) {return BST_Insert(&(*T)->lchild, key);} else if (key > (*T)->data) {return BST_Insert(&(*T)->rchild, key);} else {return false; // 重复元素}
}/*** BST查找(非递归)* 时间复杂度: 平均O(log n), 最坏O(n)* 空间复杂度: O(1)*/
BSTNode* BST_Search(BiTree T, int key) {while (T != NULL) {if (key == T->data) return T;else if (key < T->data) T = T->lchild;else T = T->rchild;}return NULL;
}/*** BST删除节点* 时间复杂度: 平均O(log n), 最坏O(n)* 空间复杂度: 平均O(log n), 最坏O(n)*/
bool BST_Delete(BiTree *T, int key) {if (T == NULL || *T == NULL) return false;if (key < (*T)->data) {return BST_Delete(&(*T)->lchild, key);} else if (key > (*T)->data) {return BST_Delete(&(*T)->rchild, key);} else {// 找到要删除的节点BSTNode *temp = *T;// 情况1:叶子节点或只有一个子节点if ((*T)->lchild == NULL) {*T = (*T)->rchild;free(temp);} else if ((*T)->rchild == NULL) {*T = (*T)->lchild;free(temp);} else {// 情况2:有两个子节点// 找到右子树的最小节点BSTNode *minNode = (*T)->rchild;while (minNode->lchild != NULL) {minNode = minNode->lchild;}// 用最小节点的值替换当前节点(*T)->data = minNode->data;// 递归删除右子树中的最小节点BST_Delete(&(*T)->rchild, minNode->data);}return true;}
}
题型2: 判断二叉树是否为BST
解答方法1: 利用中序遍历性质
/*** 方法1:中序遍历判断* 时间复杂度: O(n)* 空间复杂度: 平均O(log n), 最坏O(n)*/
bool isBST_InOrder(BiTree T) {static int prev = INT_MIN; // 静态变量记录前一个值static bool first = true; // 标记是否为第一个节点if (T == NULL) return true;// 检查左子树if (!isBST_InOrder(T->lchild)) return false;// 检查当前节点if (!first && T->data <= prev) return false;first = false;prev = T->data;// 检查右子树return isBST_InOrder(T->rchild);
}
解答方法2: 递归检查上下界
/*** 方法2:上下界递归判断* 时间复杂度: O(n)* 空间复杂度: 平均O(log n), 最坏O(n)*/
bool isBST_Recursive(BiTree T, int min, int max) {if (T == NULL) return true;// 检查当前节点是否在合法范围内if (T->data <= min || T->data >= max) return false;// 递归检查左右子树return isBST_Recursive(T->lchild, min, T->data) && isBST_Recursive(T->rchild, T->data, max);
}// 调用方式
bool isBST(BiTree T) {return isBST_Recursive(T, INT_MIN, INT_MAX);
}
题型3: BST第k小的元素
解答模版:
/*** BST中第k小的元素* 时间复杂度: O(k)* 空间复杂度: 平均O(log n), 最坏O(n)*/
int kthSmallest(BiTree T, int k) {LinkedStack stack;InitStack(&stack);BSTNode *current = T;int count = 0;while (current != NULL || !StackIsEmpty(&stack)) {while (current != NULL) {Push(&stack, current);current = current->lchild;}Pop(&stack, ¤t);count++;if (count == k) return current->data;current = current->rchild;}return -1; // 未找到
}
题型4: BST的范围和
题目要求: 计算BST中在[L,R]范围内的所有节点值之和
解答模版:
/*** BST范围求和* 时间复杂度: O(n)* 空间复杂度: 平均O(log n), 最坏O(n)*/
int rangeSumBST(BiTree T, int L, int R) {if (T == NULL) return 0;if (T->data < L) {// 当前节点值小于L,只需递归右子树return rangeSumBST(T->rchild, L, R);} else if (T->data > R) {// 当前节点值大于R,只需递归左子树return rangeSumBST(T->lchild, L, R);} else {// 当前节点在范围内,递归左右子树并加上当前值return T->data + rangeSumBST(T->lchild, L, R) + rangeSumBST(T->rchild, L, R);}
}
题型5: 有序数组构建BST
题目要求: 将有序数组转换为高度平衡的BST
解答模版:
/*** 有序数组构建平衡BST* 时间复杂度: O(n)* 空间复杂度: O(log n)*/
BSTNode* sortedArrayToBST(int arr[], int start, int end) {if (start > end) return NULL;// 总是选择中间元素作为根节点int mid = start + (end - start) / 2;BSTNode *root = (BSTNode*)malloc(sizeof(BSTNode));root->data = arr[mid];root->lchild = sortedArrayToBST(arr, start, mid - 1);root->rchild = sortedArrayToBST(arr, mid + 1, end);return root;
}
题型6: BST转换为双向链表
题目要求: 将BST转换为排序的双向链表(不允许创建新节点)
解答模版:
/*** BST转双向链表* 时间复杂度: O(n)* 空间复杂度: 平均O(log n), 最坏O(n)*/
void BSTToDLL(BiTree T, BSTNode **head, BSTNode **prev) {if (T == NULL) return;// 递归处理左子树BSTToDLL(T->lchild, head, prev);// 处理当前节点if (*prev == NULL) {*head = T; // 第一个节点} else {(*prev)->rchild = T;T->lchild = *prev;}*prev = T;// 递归处理右子树BSTToDLL(T->rchild, head, prev);
}// 调用示例
BSTNode* convertBSTToDLL(BiTree T) {BSTNode *head = NULL;BSTNode *prev = NULL;BSTToDLL(T, &head, &prev);return head;
}
题型7: BST中两节点最近公共祖先
题目要求: 在BST中找到两个节点的最近公共祖先
解答模版:
/*** BST中最近公共祖先* 时间复杂度: O(h), h为树高* 空间复杂度: O(1)非递归 / O(h)递归*/
BSTNode* lowestCommonAncestor(BSTNode* root, BSTNode* p, BSTNode* q) {// 利用BST性质while (root != NULL) {if (p->data < root->data && q->data < root->data) {root = root->lchild; // 都在左子树} else if (p->data > root->data && q->data > root->data) {root = root->rchild; // 都在右子树} else {return root; // 分别在左右子树,当前节点就是LCA}}return NULL;
}
真题1: BST验证
题目: 实现一个函数,验证二叉树是否为BST
参考答案:
/*** 验证BST* 时间复杂度: O(n)* 空间复杂度: 平均O(log n), 最坏O(n)*/
bool isValidBST(BiTree root) {return isValidBSTHelper(root, LONG_MIN, LONG_MAX);
}bool isValidBSTHelper(BiTree node, long min_val, long max_val) {if (node == NULL) return true;if (node->data <= min_val || node->data >= max_val) return false;return isValidBSTHelper(node->lchild, min_val, node->data) && isValidBSTHelper(node->rchild, node->data, max_val);
}
真题2: BST迭代器
题目: 设计BST迭代器,实现hasNext()和next()操作
参考答案:
typedef struct {LinkedStack stack;
} BSTIterator;/*** 初始化BST迭代器* 时间复杂度: O(h)* 空间复杂度: O(h)*/
void bstIteratorInit(BSTIterator *iter, BiTree root) {InitStack(&iter->stack);// 将左子树全部入栈while (root != NULL) {Push(&iter->stack, root);root = root->lchild;}
}/*** 返回下一个最小值* 时间复杂度: 平均O(1)* 空间复杂度: O(h)*/
int bstIteratorNext(BSTIterator *iter) {BSTNode *node;Pop(&iter->stack, &node);int result = node->data;// 如果有右子树,将其左子树全部入栈node = node->rchild;while (node != NULL) {Push(&iter->stack, node);node = node->lchild;}return result;
}/*** 判断是否还有下一个元素* 时间复杂度: O(1)* 空间复杂度: O(1)*/
bool bstIteratorHasNext(BSTIterator *iter) {return !StackIsEmpty(&iter->stack);
}