二叉搜索树学习记录

1. 什么是二叉搜索树

二叉搜索树(Binary Search Tree,简称 BST)是一种特殊的二叉树,它满足以下性质:

  • 若左子树不为空,则左子树上所有节点的值均小于根节点的值。
  • 若右子树不为空,则右子树上所有节点的值均大于根节点的值。
  • 左右子树本身也分别是二叉搜索树。

基于这一性质,二叉搜索树在理想情况下可以实现 O(log n) 的查找、插入和删除操作,是许多高效数据结构(如 AVL 树、红黑树)的基础。

2. 二叉搜索树的结构定义

在 C 语言中,我们通常使用结构体来定义二叉搜索树的节点。每个节点包含一个数据域和两个指针域,分别指向左孩子和右孩子。

c 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义二叉搜索树节点
typedef struct Node {
    int data;               // 数据域
    struct Node *left;      // 左孩子指针
    struct Node *right;     // 右孩子指针
} Node;

// 创建新节点
Node* createNode(int data) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

3. 二叉搜索树的插入操作

插入操作遵循二叉搜索树的性质:从根节点开始,若待插入的值小于当前节点,则向左子树递归插入;若大于当前节点,则向右子树递归插入;直到找到空位置为止。

c 复制代码
// 插入节点(递归实现)
Node* insert(Node *root, int data) {
    // 找到空位置,创建新节点
    if (root == NULL) {
        return createNode(data);
    }

    // 小于当前节点,插入左子树
    if (data < root->data) {
        root->left = insert(root->left, data);
    }
    // 大于当前节点,插入右子树
    else if (data > root->data) {
        root->right = insert(root->right, data);
    }
    // 值已存在,不重复插入(可根据需求处理)

    return root;
}

4. 二叉搜索树的查找操作

查找操作同样利用二叉搜索树的有序性:从根节点开始,若目标值等于当前节点则查找成功;若小于当前节点则向左子树查找;若大于当前节点则向右子树查找。若遇到空节点仍未找到,则说明目标值不存在。

c 复制代码
// 查找节点(递归实现)
Node* search(Node *root, int target) {
    // 空树或找到目标值
    if (root == NULL || root->data == target) {
        return root;
    }

    // 目标值小于当前节点,向左子树查找
    if (target < root->data) {
        return search(root->left, target);
    }
    // 目标值大于当前节点,向右子树查找
    return search(root->right, target);
}

5. 二叉搜索树的删除操作

删除操作是二叉搜索树中最复杂的操作,需要分三种情况讨论:

  • 情况一:待删除节点是叶子节点,直接删除即可。
  • 情况二:待删除节点只有一个孩子,用其孩子节点替代它。
  • 情况三:待删除节点有两个孩子,通常用其左子树中的最大节点或右子树中的最小节点来替代它。
c 复制代码
// 查找以 root 为根的最小节点
Node* findMin(Node *root) {
    while (root->left != NULL) {
        root = root->left;
    }
    return root;
}

// 删除节点(递归实现)
Node* deleteNode(Node *root, int target) {
    // 空树,直接返回
    if (root == NULL) {
        return root;
    }

    // 目标值小于当前节点,向左子树递归删除
    if (target < root->data) {
        root->left = deleteNode(root->left, target);
    }
    // 目标值大于当前节点,向右子树递归删除
    else if (target > root->data) {
        root->right = deleteNode(root->right, target);
    }
    // 找到待删除节点
    else {
        // 情况一:叶子节点或只有一个孩子
        if (root->left == NULL) {
            Node *temp = root->right;
            free(root);
            return temp;
        }
        else if (root->right == NULL) {
            Node *temp = root->left;
            free(root);
            return temp;
        }

        // 情况三:有两个孩子,用右子树最小节点替代
        Node *temp = findMin(root->right);
        root->data = temp->data;
        root->right = deleteNode(root->right, temp->data);
    }

    return root;
}

6. 二叉搜索树的遍历

二叉搜索树支持三种经典的深度优先遍历方式:前序遍历、中序遍历和后序遍历。其中,中序遍历二叉搜索树可以得到一个升序序列,这是二叉搜索树最重要的特性之一。

c 复制代码
// 前序遍历:根 -> 左 -> 右
void preorder(Node *root) {
    if (root == NULL) return;
    printf("%d ", root->data);
    preorder(root->left);
    preorder(root->right);
}

// 中序遍历:左 -> 根 -> 右(结果为升序)
void inorder(Node *root) {
    if (root == NULL) return;
    inorder(root->left);
    printf("%d ", root->data);
    inorder(root->right);
}

// 后序遍历:左 -> 右 -> 根
void postorder(Node *root) {
    if (root == NULL) return;
    postorder(root->left);
    postorder(root->right);
    printf("%d ", root->data);
}

7. 完整示例与测试

下面给出一个完整的 C 语言程序,演示二叉搜索树的创建、插入、查找、删除和遍历操作。

c 复制代码
#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *left;
    struct Node *right;
} Node;

Node* createNode(int data) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

Node* insert(Node *root, int data) {
    if (root == NULL) {
        return createNode(data);
    }
    if (data < root->data) {
        root->left = insert(root->left, data);
    } else if (data > root->data) {
        root->right = insert(root->right, data);
    }
    return root;
}

Node* search(Node *root, int target) {
    if (root == NULL || root->data == target) {
        return root;
    }
    if (target < root->data) {
        return search(root->left, target);
    }
    return search(root->right, target);
}

Node* findMin(Node *root) {
    while (root->left != NULL) {
        root = root->left;
    }
    return root;
}

Node* deleteNode(Node *root, int target) {
    if (root == NULL) {
        return root;
    }
    if (target < root->data) {
        root->left = deleteNode(root->left, target);
    } else if (target > root->data) {
        root->right = deleteNode(root->right, target);
    } else {
        if (root->left == NULL) {
            Node *temp = root->right;
            free(root);
            return temp;
        } else if (root->right == NULL) {
            Node *temp = root->left;
            free(root);
            return temp;
        }
        Node *temp = findMin(root->right);
        root->data = temp->data;
        root->right = deleteNode(root->right, temp->data);
    }
    return root;
}

void inorder(Node *root) {
    if (root == NULL) return;
    inorder(root->left);
    printf("%d ", root->data);
    inorder(root->right);
}

void freeTree(Node *root) {
    if (root == NULL) return;
    freeTree(root->left);
    freeTree(root->right);
    free(root);
}

int main() {
    Node *root = NULL;
    int values[] = {50, 30, 70, 20, 40, 60, 80};
    int n = sizeof(values) / sizeof(values[0]);

    // 构建二叉搜索树
    for (int i = 0; i < n; i++) {
        root = insert(root, values[i]);
    }

    printf("中序遍历结果:");
    inorder(root);
    printf("\n");

    // 查找操作
    Node *found = search(root, 40);
    if (found != NULL) {
        printf("查找 40:找到\n");
    } else {
        printf("查找 40:未找到\n");
    }

    // 删除操作
    root = deleteNode(root, 30);
    printf("删除 30 后中序遍历:");
    inorder(root);
    printf("\n");

    // 释放内存
    freeTree(root);
    return 0;
}

8. 复杂度分析与总结

二叉搜索树的性能取决于树的高度:

操作 平均时间复杂度 最坏时间复杂度
查找 O(log n) O(n)
插入 O(log n) O(n)
删除 O(log n) O(n)

当二叉搜索树退化为一条链时(例如按升序插入数据),其性能会退化为 O(n)。为了解决这一问题,后续发展出了 AVL 树、红黑树等自平衡二叉搜索树,它们通过旋转操作保持树的高度平衡,从而保证操作始终在 O(log n) 时间内完成。

二叉搜索树是数据结构学习中的重要基石,理解其原理和实现,对于掌握更复杂的平衡树结构大有裨益。

相关推荐
无锡银洲自动化29 分钟前
煤粉测点频繁堵管?FD 防堵风压取样器现场调试小结
笔记·产品运营
水饺编程40 分钟前
第2章:Linux 基础,重启命令
linux·c语言·汇编
小O的算法实验室1 小时前
ASOC,分层分数阶粒子群算法+无人机电场路径规划
算法
傅科摆 _ py1 小时前
链表力扣复习
数据结构·leetcode·链表
ACP广源盛139246256731 小时前
Type-C 扩展坞选型笔记:DP1.4a 转 HDMI2.0 桥接方案 GSV2201E @ACP评估
笔记·硬件架构·硬件工程·视频·hdmi·国产芯片
重生之小比特1 小时前
【算法拾光】二分查找|搜索插入位置 + x 的平方根
算法
智购科技自动售卖机厂家1 小时前
双摄像头方案F1-score只有0.85,排查发现是上下视角的融合逻辑写反了~YH
python·单片机·嵌入式硬件·算法·eclipse
xian_wwq1 小时前
【学习笔记-一文读懂系列】读懂GBZ-195-2026《人工智能 工业智能体参考架构》
笔记·学习
inrichtt2 小时前
第十一课时:串口中断接收与回调函数实战解析
c语言·数据结构·stm32·单片机·嵌入式硬件