【数据结构之二叉搜索树(BST)】


一、前言

在数据结构中,二叉搜索树(Binary Search Tree,简称 BST) 是一种非常重要的树形结构。它在查找、插入和删除操作中具有良好的性能,广泛应用于数据库索引、内存管理、集合操作等场景。本文将详细介绍 BST 的概念、基本操作、实现方式及其复杂度分析。


二、二叉搜索树的定义

二叉搜索树是一种满足以下特性的数据结构:

  • 每个节点最多有两个子节点,分别是左子节点右子节点
  • 左子树上所有节点的值均小于根节点的值。
  • 右子树上所有节点的值均大于根节点的值。
  • 左右子树本身也是二叉搜索树。

示例图:

         10  
       /    \  
     5      15  
    / \    /  \  
   3   7  12  18  
  • 根节点:10
  • 左子树:{3, 5, 7}
  • 右子树:{12, 15, 18}

三、二叉搜索树的基本操作

1. 插入节点

插入操作遵循以下规则:

  • 若树为空,则创建根节点。
  • 若插入值小于当前节点,递归插入到左子树。
  • 若插入值大于当前节点,递归插入到右子树。

C语言实现:

#include <stdio.h>
#include <stdlib.h>

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

// 创建新节点
Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->left = 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 {
        root->right = insert(root->right, data);
    }
    return root;
}

// 中序遍历(用于验证 BST)
void inorder(Node* root) {
    if (root != NULL) {
        inorder(root->left);
        printf("%d ", root->data);
        inorder(root->right);
    }
}

int main() {
    Node* root = NULL;
    root = insert(root, 10);
    insert(root, 5);
    insert(root, 15);
    insert(root, 3);
    insert(root, 7);
    insert(root, 12);
    insert(root, 18);

    printf("BST Inorder Traversal: ");
    inorder(root);  // 3 5 7 10 12 15 18
    return 0;
}

2. 查找节点

查找操作遵循以下规则:

  • 若当前节点值等于目标值,则返回该节点。
  • 若目标值小于当前节点,递归在左子树查找。
  • 若目标值大于当前节点,递归在右子树查找。

C语言实现:

// 查找节点
Node* search(Node* root, int key) {
    if (root == NULL || root->data == key) {
        return root;
    }
    if (key < root->data) {
        return search(root->left, key);
    }
    return search(root->right, key);
}

int main() {
    Node* root = NULL;
    root = insert(root, 10);
    insert(root, 5);
    insert(root, 15);

    int key = 5;
    Node* result = search(root, key);
    if (result != NULL) {
        printf("Found node with value: %d\n", result->data);
    } else {
        printf("Node not found.\n");
    }
    return 0;
}

3. 删除节点

删除节点分为三种情况:

  1. 叶子节点:直接删除即可。
  2. 只有一个子节点:将父节点指向子节点。
  3. 有两个子节点
    • 找到中序后继节点(右子树中最小节点)。
    • 将目标节点替换为后继节点。
    • 删除后继节点。

C语言实现:

// 寻找最小值节点
Node* minValueNode(Node* node) {
    Node* current = node;
    while (current && current->left != NULL) {
        current = current->left;
    }
    return current;
}

// 删除节点
Node* deleteNode(Node* root, int key) {
    if (root == NULL) return root;

    if (key < root->data) {
        root->left = deleteNode(root->left, key);
    } else if (key > root->data) {
        root->right = deleteNode(root->right, key);
    } 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 = minValueNode(root->right);
        root->data = temp->data;
        root->right = deleteNode(root->right, temp->data);
    }
    return root;
}

四、时间与空间复杂度分析

操作平均时间复杂度最坏时间复杂度空间复杂度
插入O(log n)O(n)O(n)
查找O(log n)O(n)O(1)
删除O(log n)O(n)O(1)
中序遍历O(n)O(n)O(1)
  • 平均情况下,BST 是平衡的,查找、插入和删除的时间复杂度为 O(log n)。
  • 最坏情况下,BST 会退化为链表,时间复杂度为 O(n)。

优化方式

  • 使用平衡二叉树(如 AVL 树、红黑树)可以防止退化。
  • 使用自平衡树可保证 O(log n) 的复杂度。

五、二叉搜索树的应用

  1. 查找与排序
    • BST 中序遍历可以生成有序序列。
  2. 集合与映射
    • BST 可用于实现集合和映射操作。
  3. 数据库索引
    • BST 常用于数据库索引,以提高查询效率。
  4. 区间查询
    • BST 可用于区间查询操作,如寻找范围内的数据。

六、总结

二叉搜索树(BST)是一种重要的数据结构,支持高效的插入、查找和删除操作。
在实际应用中,BST 常用于实现集合操作、数据库索引和排序算法。
为了防止 BST 退化为链表,通常使用 AVL 树或红黑树等平衡树进行优化。

重点回顾

  • BST 的定义与特点。
  • 基本操作:插入、查找、删除。
  • C语言实现示例。
  • 时间与空间复杂度分析。
  • BST 的实际应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wdwc2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值