BST二叉搜索树——数据结构系列教程(c++版)

梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)


  二叉搜索树(Binary Search Tree,简称BST)是一种满足特定有序性规则的二叉树,也是实现高效查找、插入、删除操作的基础数据结构,广泛应用于数据库索引、集合/映射等场景。本教程基于链表实现二叉搜索树,从核心原理、代码结构到实战使用,全面讲解二叉搜索树的原理与实现,功能包含插入、查找、删除、四种遍历(前序 / 中序 / 后序 /层序)、内存释放等核心功能。

教程目录导航

一、二叉搜索树的核心原理

1.1 二叉搜索树(BST)特性

  1. 左子树所有节点值 < 根节点值;
  2. 右子树所有节点值 > 根节点值;
  3. 左右子树也满足 BST 特性(无重复值)。

1.2 关键特征

  1. BST中序遍历的结果为升序序列(这是BST最核心的标识)。

演示动画

1.3 优缺点分析

优点 缺点
查找、插入、删除平均时间复杂度为O(log₂n)(树平衡时) 若插入数据有序(如1,2,3,4,5),BST会退化成链表,时间复杂度变为O(n)
中序遍历可直接得到升序序列,无需额外排序 无自平衡机制,极端场景下性能大幅下降
链表存储结构,容量无限制 删除节点逻辑相对复杂(需处理3种不同情况)

1.4 时间复杂度

操作 平均情况 最坏情况(退化为链表)
查找 O(log₂n) O(n)
插入 O(log₂n) O(n)
删除 O(log₂n) O(n)
空间复杂度 O(n)(存储n个节点) O(n)

1.5 存储结构

二叉搜索树结构是一对多的关系,除了树根之外,每一个节点有唯一的直接前驱(父亲),除了叶子之外,每一个节点有一个或两个直接后继(孩子)。

可以采用顺序存储和链式存储两种形式:

(1)顺序存储(数组)

把根节点存储在下标 i = 1 的位置,把左子节点存储在下标 2 * i = 2 的位置,右子节点存储在 2 * i + 1 = 3 的位置。树为满二叉树完全二叉树时不会浪费太多存储空间。

(1)链式存储(结构体)

每一个节点有三个域,即数据域data、lchild左节点地址、rchild右节点地址。

二、代码结构解析

2.1 整体架构

提供的代码是模板化的二叉搜索树实现(支持任意类型),采用C++结构体封装,分为头文件(声明)和源文件(实现)两部分,核心结构如下:

模块 作用 关键结构/函数
BST节点结构体 存储数据、左节点指针、右节点指针 BSTNode<T>(模板泛型)
二叉搜索树结构体 封装所有操作 LinkedBSTree<T>(模板类)

2.2 关键结构体详解

(1)BST节点结构体(BSTNode)

template <typename T>
struct BSTNode {
    T data;
    BSTNode* left;
    BSTNode* right;
};

(3)二叉搜索树结构体(LinkedBSTree)

分为私有成员(内部实现)和公有成员(对外接口):

template <typename T>
struct LinkedBSTree{
    //------------------------------------------------------------------------------------------------------
    //                                          私有成员
    // 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
    //------------------------------------------------------------------------------------------------------
    private:

        //---------------声明私有成员变量---------------

        BSTNode<T>* root;          // 根节点指针
        int level;                // 用于跟踪搜索树的层次
        int depth;                // 用于跟踪搜索树的深度
        int qty;                  // 用于跟踪搜索树的节点数量

        //---------------声明私有成员函数---------------

        BSTNode<T>* createTreeNode(const T& val);// 创建新的树节点
        BSTNode<T>* findMin(BSTNode<T>* node);// 找右子树的最小节点
        BSTNode<T>* insertNode(BSTNode<T>* node, const T& val);// 插入节点(递归版本)
        BSTNode<T>* insertNodeIter(BSTNode<T>* node, const T& val);// 插入节点(迭代版本)
        BSTNode<T>* deleteNode(BSTNode<T>* node, const T& val);// 删除节点(递归版本)
        BSTNode<T>* deleteNodeIter(BSTNode<T>* node, const T& val);// 删除节点(迭代版本)
        T searchNode(BSTNode<T>* node, const T& val);// 查找节点// 查找节点(递归版本)
        T searchNodeIter(BSTNode<T>* node, const T& val);// 查找节点(迭代版本)
        void preOrder(BSTNode<T>* node);// 前序遍历(根 → 左 → 右)
        void inOrder(BSTNode<T>* node);// 中序遍历(左 → 根 → 右)→ 升序输出
        void postOrder(BSTNode<T>* node);// 后序遍历(左 → 右 → 根)
        void levelOrder(BSTNode<T>* node);// 层序遍历(从上到下、从左到右)
        void destroyTree(BSTNode<T>* node);// 销毁整棵树(防止内存泄漏)

    // ------------------------------------------------------------------------------------------------------
    //                                          公共成员
    // 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
    //-------------------------------------------------------------------------------------------------------
    public:

        //---------------声明公共成员函数---------------

        // 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
        LinkedBSTree() {
            level = depth = qty = 0;
            root = nullptr; // 初始化为空树
        }

        int isEmpty();// 判断搜索树是否为空
        int isFull();// 判断搜索树是否已满
        void insertNode(const T& val);// 插入节点
        void deleteNode(const T& val);// 删除节点
        bool searchNode(const T& val);// 查找节点
        void preOrder();// 前序遍历(根 → 左 → 右)
        void inOrder();// 中序遍历(左 → 根 → 右)→ 升序输出
        void postOrder();// 后序遍历(左 → 右 → 根)
        void levelOrder();// 层序遍历(从上到下、从左到右)
        void destroyTree();// 手动销毁整棵树(防止内存泄漏)

        // 析构函数:自动销毁树,避免内存泄漏
        ~LinkedBSTree() {
            destroyTree();
        }
};

三、核心操作实现详解

3.1 遍历操作

BST的遍历分为前序、中序、后序、层次,其中中序遍历是核心(升序输出)。

(1)前序遍历(preOrder)

从node节点开始,根 → 左 → 右的顺序遍历树,一般从root节点开始。采用递归的方式实现,如果节点数比较大建议采用迭代方式实现,防止内存溢出。

template <typename T>
void LinkedBSTree<T>::preOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;
    printf("%d ", node->data);
    preOrder(node->left);
    preOrder(node->right);
}

(2)中序遍历(inOrder)

从node节点开始,左 → 根 → 右的顺序遍历树,一般从root节点开始。采用递归的方式实现

template <typename T>
void LinkedBSTree<T>::inOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;
    inOrder(node->left);
    printf("%d ", node->data);
    inOrder(node->right);
}

(3)后序遍历(postOrder)

从node节点开始,左 → 右 → 根的顺序遍历树,一般从root节点开始。采用递归的方式实现

template <typename T>
void LinkedBSTree<T>::postOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;
    postOrder(node->left);
    postOrder(node->right);
    printf("%d ", node->data);
}

(4)后序遍历(levelOrder)

从node节点开始,从上到下、从左到右顺序遍历树。采用迭代+队列的方式实现

template <typename T>
void LinkedBSTree<T>::levelOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;

    std::queue<BSTNode<T>*> queues;
    queues.push(node); // 根节点入队

    while (!queues.empty()) {
        BSTNode<T>* curr = queues.front(); // 获取队头节点
        queues.pop();// 出队头节点
        printf("%d ", curr->data); // 输出当前节点值

        // 左子节点入队(先左后右)
        if (curr->left != NULL) {
            queues.push(curr->left);
        }
        // 右子节点入队
        if (curr->right != NULL) {
            queues.push(curr->right);
        }
    }
}

3.2 插入节点(insertNode)

插入流程:

  1. 递归或迭代找到空节点位置(终止条件);
  2. 比较值大小,决定插入左/右子树;
  3. 重复值直接返回(BST默认不存储重复值);
  4. 更新节点数量,返回新节点/原节点。

// 插入节点(递归版本)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::insertNode(BSTNode<T>* node, const T& val)
{
    if (node == nullptr) { // 空节点,创建新节点        
        return createTreeNode(val);
    }
    if (val < node->data) { // 小于当前节点,插入左子树
        node->left = insertNode(node->left, val);
    } else if (val > node->data) { // 大于当前节点,插入右子树
        node->right = insertNode(node->right, val);
    }
    // 等于当前节点(重复值),BST 不存储重复值,直接返回原节点
    return node;
}

// 插入节点(迭代版本)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::insertNodeIter(BSTNode<T>* node, const T& val)
{
    // 处理根节点为空的特殊情况
    if (node == nullptr) {
        return createTreeNode(val);
    }

    BSTNode<T>* current = node;  // 遍历指针,从根节点开始
    BSTNode<T>* parent = nullptr; // 记录当前节点的父节点

    // 迭代查找插入位置
    while (current != nullptr) {
        parent = current; // 更新父节点为当前节点

        if (val < current->data) { // 小于当前节点,向左子树查找
            current = current->left;
        } else if (val > current->data) { // 大于当前节点,向右子树查找
            current = current->right;
        } else {
            // 找到重复值,直接返回原根节点(不插入)
            return node;
        }
    }

    // 找到插入位置,创建新节点并挂载到父节点的左/右子树
    BSTNode<T>* newNode = createTreeNode(val);
    if (val < parent->data) {
        parent->left = newNode;
    } else {
        parent->right = newNode;
    }

    // 返回原根节点(根节点未变,除非一开始就是空树)
    return node;
}
创建新节点(辅助函数)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::createTreeNode(const T& val)
{
    BSTNode<T>* node = new BSTNode<T>(); // 动态分配模板类型节点
    if (node == nullptr) { // 内存分配失败检查
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    node->data = val;
    node->left = nullptr;
    node->right = nullptr;
    qty++;
    return node;
}

3.3 删除操作(deleteNode)

删除流程:

  1. 定位节点:递归找到值匹配的节点;
  2. 处理删除
    • 情况1(叶子节点):直接释放节点,返回空;
    • 情况2(单子女节点):用子节点替换当前节点,释放当前节点;
    • 情况3(双子女节点):找右子树最小值(后继节点)替换当前节点值,再删除后继节点;
  3. 更新节点数量,返回更新后的节点指针。

// 删除节点(递归版本)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::deleteNode(BSTNode<T>* node, const T& val)
{
    if (node == nullptr) { // 未找到要删除的节点
        return nullptr;
    }

    // 1. 定位要删除的节点
    if (val < node->data) {
        node->left = deleteNode(node->left, val);
    } else if (val > node->data) {
        node->right = deleteNode(node->right, val);
    } else {
        // 2. 处理删除逻辑(分3种情况)
        // 情况1:叶子节点(无左右子树)
        if (node->left == nullptr && node->right == nullptr) {
            free(node);
            qty--;
            return nullptr;
        }
        // 情况2:只有一个子树
        else if (node->left == nullptr) { // 只有右子树
            BSTNode<T>* temp = node->right;
            free(node);
            qty--;
            return temp;
        } else if (node->right == nullptr) { // 只有左子树
            BSTNode<T>* temp = node->left;
            free(node);
            qty--;
            return temp;
        }
        // 情况3:有两个子树 → 找右子树最小节点(后继)替换
        else {
            BSTNode<T>* minRight = findMin(node->right);
            node->data = minRight->data; // 替换值
            node->right = deleteNode(node->right, minRight->data); // 删除后继节点
        }
    }
    return node;
}

// 删除节点(迭代版本)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::deleteNodeIter(BSTNode<T>* node, const T& val)
{
    // 根节点为空,直接返回
    if (node == nullptr) {
        return nullptr;
    }

    BSTNode<T>* current = node;    // 遍历指针,寻找待删除节点
    BSTNode<T>* parent = nullptr;  // 待删除节点的父节点
    bool isLeftChild = false;      // 标记待删除节点是父节点的左/右孩子

    // 第一步:迭代查找待删除节点,并记录其父节点和左右孩子标记
    while (current != nullptr && current->data != val) {
        parent = current;
        if (val < current->data) {
            current = current->left;
            isLeftChild = true;
        } else {
            current = current->right;
            isLeftChild = false;
        }
    }

    // 未找到待删除节点,直接返回原根节点
    if (current == nullptr) {
        return node;
    }

    // 第二步:处理删除逻辑(分3种情况)
    BSTNode<T>* nodeToDelete = current;
    BSTNode<T>* replacement = nullptr; // 替换待删除节点的节点

    // 情况1:叶子节点(无左右子树)
    if (current->left == nullptr && current->right == nullptr) {
        replacement = nullptr;
    }
    // 情况2:只有一个子树
    else if (current->left == nullptr) { // 只有右子树
        replacement = current->right;
    } else if (current->right == nullptr) { // 只有左子树
        replacement = current->left;
    }
    // 情况3:有两个子树 → 找右子树最小节点(后继)替换
    else {
        // 迭代查找右子树的最小节点(最左节点)
        BSTNode<T>* minParent = current;
        BSTNode<T>* minNode = current->right;
        while (minNode->left != nullptr) {
            minParent = minNode;
            minNode = minNode->left;
        }

        // 替换待删除节点的值
        current->data = minNode->data;
        // 处理最小节点的替换(最小节点要么是叶子,要么只有右子树)
        if (minParent == current) { // 最小节点是待删除节点的直接右孩子
            minParent->right = minNode->right;
        } else { // 最小节点在右子树的左分支
            minParent->left = minNode->right;
        }
        // 要删除的节点变为找到的最小节点
        nodeToDelete = minNode;
        // 原待删除节点无需替换(值已更新)
        replacement = current;
    }

    // 第三步:更新父节点的子节点指针,并释放内存
    if (replacement != current) { // 非双孩子情况,需要更新父节点指针
        if (parent == nullptr) { // 待删除节点是根节点
            node = replacement;
        } else if (isLeftChild) { // 待删除节点是父节点的左孩子
            parent->left = replacement;
        } else { // 待删除节点是父节点的右孩子
            parent->right = replacement;
        }
    }

    // 释放待删除节点的内存
    free(nodeToDelete);
    qty--;

    // 返回删除后的根节点
    return node;
}

找右子树的最小节点(findMin)辅助函数

template <typename T>
BSTNode<T>* LinkedBSTree<T>::findMin(BSTNode<T>* node)
{
    while (node->left != nullptr) {
        node = node->left;
    }
    return node;
}

四、实战使用示例

4.1 基础类型(int)使用示例


#include <iostream>
#include "LinkedBSTree.h"

int main() {
    // 1. 创建bst对象
    LinkedBSTree<int> bst;

    // 2. 插入节点
    bst.insertNode(10);
    bst.insertNode(20);
    bst.insertNode(5);
    bst.insertNode(30);

    // 3. 中序遍历(升序输出)
    std::cout << "中序遍历结果:" << std::endl;
    bst.inOrder();

    // 4. 查找节点
    if (bst.searchNode(20)) {
        std::cout << "找到节点20" << std::endl;
    }

    // 5. 删除节点
    bst.deleteNode(10);
    std::cout << "删除10后中序遍历:" << std::endl;
    bst.inOrder();

    // 6. 销毁树
    bst.destroyTree();

    return 0;
}

4.2 自定义类型(Student)使用示例

需先定义Student类,并重载比较运算符(<==):


#include <iostream>
#include "Entitys.h"
#include "LinkedBSTree.h"

// 使用示例
int main() {
    LinkedBSTree<Student> studentBst;

    // 插入学生节点
    studentBst.insertNode({1001,"Eric", "2012-05-18", "男", "汉", "湖南省湘潭县石潭镇", 400, "石潭傎芙蓉中学", "36","在读"});
    studentBst.insertNode({1002,"Bob", "2012-05-18", "男", "汉", "湖南省湘潭县石潭镇", 400, "石潭傎芙蓉中学", "36","在读"});
    studentBst.insertNode({1003,"Charlie", "2012-05-18", "男", "汉", "湖南省湘潭县石潭镇", 400, "石潭傎芙蓉中学", "36","在读"});

    // 中序遍历(按ID升序)
    studentBst.inOrder();

    // 删除学生
    studentBst.deleteNode({1003,"", "", "", "", "", 0, "", "",""}); // 仅需ID匹配

    return 0;
}

五、完整可运行代码

5.1 Entitys.h 头文件


#ifndef ENTITYS_H_INCLUDED
#define ENTITYS_H_INCLUDED

//************************************************************************************************************************************************************************
//                                                                      自定义类型
//************************************************************************************************************************************************************************

//========================================================================================================================================================================
//                                                                    学生结构体(Student)
//========================================================================================================================================================================
struct Student {
    int id;// 学号
    std::string name;// 姓名
    std::string dob;// 出生日期
    std::string sex;// 性别
    std::string gender;// 民族
    std::string address;// 地址
    float score;// 入学总分
    std::string school;// 学校
    std::string team;// 班级
    std::string status;// 状态

    bool operator<(const Student& other) const { return id < other.id; }
    bool operator>(const Student& other) const { return id > other.id; }
    bool operator==(const Student& other) const { return id == other.id; }
    bool operator!=(const Student& other) const { return id != other.id; }

    friend std::ostream& operator<<(std::ostream& os, const Student& s) {
        os << "[" << s.id<< ", " << s.name << ", " << s.dob << ", " << s.sex << ", " << s.gender  << ", " << s.address << ", " << s.score<< ", " << s.school<< ", " << s.team<< ", " << s.status << "]";
        return os;
    }
};

//========================================================================================================================================================================
//
//                                                                    学生索引结构体(Student)
//
//========================================================================================================================================================================
struct StudentIndex {
    int id;// 学号
    int row;// 行号

    bool operator<(const StudentIndex& other) const { return id < other.id; }
    bool operator>(const StudentIndex& other) const { return id > other.id; }
    bool operator==(const StudentIndex& other) const { return id == other.id; }
    bool operator!=(const StudentIndex& other) const { return id != other.id; }

    friend std::ostream& operator<<(std::ostream& os, const StudentIndex& i) {
        os << "[" << i.id << ", " << i.row<< "]";
        return os;
    }
};

//========================================================================================================================================================================
//                                                                    迷宫坐标结构体(Pos)
//========================================================================================================================================================================
struct Pos{
    int x;     //x坐标
    int y;    //y坐标
    int step; //步数
};

//========================================================================================================================================================================
//                                                                    打印任务结构体(PrintTask)
//========================================================================================================================================================================
struct PrintTask{
    int taskId;     // 任务ID
    char content[50]; // 打印内容
};

#endif // ENTITYS_H_INCLUDED
        

5.2 LinkedBSTree.h 头文件


#ifndef LINKEDBSTREE_H_INCLUDED
#define LINKEDBSTREE_H_INCLUDED

#include <queue>  // STL队列
#include "Entitys.h"

//========================================================================================================================================================================
//
//                                                                 BST节点结构体(BSTNode)
//
//========================================================================================================================================================================
template <typename T>
struct BSTNode {
    T data;
    BSTNode* left;
    BSTNode* right;
};

//========================================================================================================================================================================
//
//                                                                二叉搜索树结构体(LinkedBSTree)
//
//========================================================================================================================================================================
template <typename T>
struct LinkedBSTree{
    //------------------------------------------------------------------------------------------------------
    //                                          私有成员
    // 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
    //------------------------------------------------------------------------------------------------------
    private:

        //---------------声明私有成员变量---------------

        BSTNode<T>* root;          // 根节点指针
        int level;                // 用于跟踪搜索树的层次
        int depth;                // 用于跟踪搜索树的深度
        int qty;                  // 用于跟踪搜索树的节点数量

        //---------------声明私有成员函数---------------

        BSTNode<T>* createTreeNode(const T& val);// 创建新的树节点
        BSTNode<T>* findMin(BSTNode<T>* node);// 找右子树的最小节点
        BSTNode<T>* insertNode(BSTNode<T>* node, const T& val);// 插入节点(递归版本)
        BSTNode<T>* insertNodeIter(BSTNode<T>* node, const T& val);// 插入节点(迭代版本)
        BSTNode<T>* deleteNode(BSTNode<T>* node, const T& val);// 删除节点(递归版本)
        BSTNode<T>* deleteNodeIter(BSTNode<T>* node, const T& val);// 删除节点(迭代版本)
        T searchNode(BSTNode<T>* node, const T& val);// 查找节点(递归版本)
        T searchNodeIter(BSTNode<T>* node, const T& val);// 查找节点(迭代版本)
        void preOrder(BSTNode<T>* node);// 前序遍历(根 → 左 → 右)
        void inOrder(BSTNode<T>* node);// 中序遍历(左 → 根 → 右)→ 升序输出
        void postOrder(BSTNode<T>* node);// 后序遍历(左 → 右 → 根)
        void levelOrder(BSTNode<T>* node);// 层序遍历(从上到下、从左到右)
        void destroyTree(BSTNode<T>* node);// 销毁整棵树(防止内存泄漏)

    // ------------------------------------------------------------------------------------------------------
    //                                          公共成员
    // 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
    //-------------------------------------------------------------------------------------------------------
    public:

        //---------------声明公共成员函数---------------

        // 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
        LinkedBSTree() {
            level = depth = qty = 0;
            root = nullptr; // 初始化为空树
        }

        BSTNode<T>* getRoot();// 获取root指针
        int isEmpty();// 判断搜索树是否为空
        int isFull();// 判断搜索树是否已满
        void insertNode(const T& val);// 插入节点
        void deleteNode(const T& val);// 删除节点
        T searchNode(const T& val);// 查找节点
        void preOrder();// 前序遍历(根 → 左 → 右)
        void inOrder();// 中序遍历(左 → 根 → 右)→ 升序输出
        void postOrder();// 后序遍历(左 → 右 → 根)
        void levelOrder();// 层序遍历(从上到下、从左到右)
        void destroyTree();// 手动销毁整棵树(防止内存泄漏)

        // 析构函数:自动销毁树,避免内存泄漏
        ~LinkedBSTree() {
            destroyTree();
        }
};

#endif // LINKEDBSTREE_H_INCLUDED

5.3 LinkedBSTree.cpp 程序代码


#include <iostream>
#include <cstdlib> 
#include "LinkedBSTree.h"

//---------------实现私有成员函数---------------

// 创建新的树节点
template <typename T>
BSTNode<T>* LinkedBSTree<T>::createTreeNode(const T& val)
{
    BSTNode<T>* node = new BSTNode<T>(); // 动态分配模板类型节点
    if (node == nullptr) { // 内存分配失败检查
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    node->data = val;
    node->left = nullptr;
    node->right = nullptr;
    qty++; // 节点数+1
    return node;
}

// 找右子树的最小节点
template <typename T>
BSTNode<T>* LinkedBSTree<T>::findMin(BSTNode<T>* node)
{
    while (node->left != nullptr) {
        node = node->left;
    }
    return node;
}

// 插入节点(递归版本)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::insertNode(BSTNode<T>* node, const T& val)
{
    if (node == nullptr) { // 空节点,创建新节点
        qty++;
        return createTreeNode(val);
    }
    if (val < node->data) { // 小于当前节点,插入左子树
        node->left = insertNode(node->left, val);
    } else if (val > node->data) { // 大于当前节点,插入右子树
        node->right = insertNode(node->right, val);
    }
    // 等于当前节点(重复值),BST 不存储重复值,直接返回原节点
    return node;
}

// 插入节点(迭代版本)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::insertNodeIter(BSTNode<T>* node, const T& val)
{
    // 处理根节点为空的特殊情况
    if (node == nullptr) {
        return createTreeNode(val);
    }

    BSTNode<T>* current = node;  // 遍历指针,从根节点开始
    BSTNode<T>* parent = nullptr; // 记录当前节点的父节点

    // 迭代查找插入位置
    while (current != nullptr) {
        parent = current; // 更新父节点为当前节点

        if (val < current->data) { // 小于当前节点,向左子树查找
            current = current->left;
        } else if (val > current->data) { // 大于当前节点,向右子树查找
            current = current->right;
        } else {
            // 找到重复值,直接返回原根节点(不插入)
            return node;
        }
    }

    // 找到插入位置,创建新节点并挂载到父节点的左/右子树
    BSTNode<T>* newNode = createTreeNode(val);
    if (val < parent->data) {
        parent->left = newNode;
    } else {
        parent->right = newNode;
    }

    // 返回原根节点(根节点未变,除非一开始就是空树)
    return node;
}

// 删除节点(递归实现)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::deleteNode(BSTNode<T>* node, const T& val)
{
    if (node == nullptr) { // 未找到要删除的节点
        return nullptr;
    }

    // 1. 定位要删除的节点
    if (val < node->data) {
        node->left = deleteNode(node->left, val);
    } else if (val > node->data) {
        node->right = deleteNode(node->right, val);
    } else {
        // 2. 处理删除逻辑(分3种情况)
        // 情况1:叶子节点(无左右子树)
        if (node->left == nullptr && node->right == nullptr) {
            free(node);
            qty--;
            return nullptr;
        }
        // 情况2:只有一个子树
        else if (node->left == nullptr) { // 只有右子树
            BSTNode<T>* temp = node->right;
            free(node);
            qty--;
            return temp;
        } else if (node->right == nullptr) { // 只有左子树
            BSTNode<T>* temp = node->left;
            free(node);
            qty--;
            return temp;
        }
        // 情况3:有两个子树 → 找右子树最小节点(后继)替换
        else {
            BSTNode<T>* minRight = findMin(node->right);
            node->data = minRight->data; // 替换值
            node->right = deleteNode(node->right, minRight->data); // 删除后继节点
        }
    }
    return node;
}

// 删除节点(迭代版本)
template <typename T>
BSTNode<T>* LinkedBSTree<T>::deleteNodeIter(BSTNode<T>* node, const T& val)
{
    // 根节点为空,直接返回
    if (node == nullptr) {
        return nullptr;
    }

    BSTNode<T>* current = node;    // 遍历指针,寻找待删除节点
    BSTNode<T>* parent = nullptr;  // 待删除节点的父节点
    bool isLeftChild = false;      // 标记待删除节点是父节点的左/右孩子

    // 第一步:迭代查找待删除节点,并记录其父节点和左右孩子标记
    while (current != nullptr && current->data != val) {
        parent = current;
        if (val < current->data) {
            current = current->left;
            isLeftChild = true;
        } else {
            current = current->right;
            isLeftChild = false;
        }
    }

    // 未找到待删除节点,直接返回原根节点
    if (current == nullptr) {
        return node;
    }

    // 第二步:处理删除逻辑(分3种情况)
    BSTNode<T>* nodeToDelete = current;
    BSTNode<T>* replacement = nullptr; // 替换待删除节点的节点

    // 情况1:叶子节点(无左右子树)
    if (current->left == nullptr && current->right == nullptr) {
        replacement = nullptr;
    }
    // 情况2:只有一个子树
    else if (current->left == nullptr) { // 只有右子树
        replacement = current->right;
    } else if (current->right == nullptr) { // 只有左子树
        replacement = current->left;
    }
    // 情况3:有两个子树 → 找右子树最小节点(后继)替换
    else {
        // 迭代查找右子树的最小节点(最左节点)
        BSTNode<T>* minParent = current;
        BSTNode<T>* minNode = current->right;
        while (minNode->left != nullptr) {
            minParent = minNode;
            minNode = minNode->left;
        }

        // 替换待删除节点的值
        current->data = minNode->data;
        // 处理最小节点的替换(最小节点要么是叶子,要么只有右子树)
        if (minParent == current) { // 最小节点是待删除节点的直接右孩子
            minParent->right = minNode->right;
        } else { // 最小节点在右子树的左分支
            minParent->left = minNode->right;
        }
        // 要删除的节点变为找到的最小节点
        nodeToDelete = minNode;
        // 原待删除节点无需替换(值已更新)
        replacement = current;
    }

    // 第三步:更新父节点的子节点指针,并释放内存
    if (replacement != current) { // 非双孩子情况,需要更新父节点指针
        if (parent == nullptr) { // 待删除节点是根节点
            node = replacement;
        } else if (isLeftChild) { // 待删除节点是父节点的左孩子
            parent->left = replacement;
        } else { // 待删除节点是父节点的右孩子
            parent->right = replacement;
        }
    }

    // 释放待删除节点的内存
    free(nodeToDelete);
    qty--;

    // 返回删除后的根节点
    return node;
}

// 查找节点(递归实现)
template <typename T>
bool LinkedBSTree<T>::searchNode(BSTNode<T>* node, const T& val)
{
    if (node == nullptr) { // 未找到
        return false;
    }
    if (val == node->data) { // 找到目标值
        return true;
    } else if (val < node->data) { // 往左子树找
        return searchNode(node->left, val);
    } else { // 往右子树找
        return searchNode(node->right, val);
    }
}

// 查找节点(迭代版本)
template <typename T>
T LinkedBSTree<T>::searchNodeIter(BSTNode<T>* node, const T& val)
{
    // 初始化遍历指针,从传入的节点(通常是根节点)开始
    BSTNode<T>* current = node;

    // 迭代遍历:只要当前节点不为空,就继续查找
    while (current != nullptr) {
        if (val == current->data) {
            // 找到目标值,直接返回
            return current->data;
        } else if (val < current->data) {
            // 目标值更小,向左子树查找
            current = current->left;
        } else {
            // 目标值更大,向右子树查找
            current = current->right;
        }
    }

    // 遍历到空节点,说明未找到,返回T类型的默认值(和递归版本一致)
    return T();
}

// 前序遍历(根 → 左 → 右)
template <typename T>
void LinkedBSTree<T>::preOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;
    printf("%d ", node->data);
    preOrder(node->left);
    preOrder(node->right);
}

// 中序遍历(左 → 根 → 右)→ 升序输出
template <typename T>
void LinkedBSTree<T>::inOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;
    inOrder(node->left);
    printf("%d ", node->data);
    inOrder(node->right);
}

// 后序遍历(左 → 右 → 根)
template <typename T>
void LinkedBSTree<T>::postOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;
    postOrder(node->left);
    postOrder(node->right);
    printf("%d ", node->data);
}

// 层序遍历(从上到下、从左到右)
void LinkedBSTree<T>::levelOrder(BSTNode<T>* node)
{
    if (node == nullptr) return;

    std::queue<BSTNode<T>*> queues;
    queues.push(node); // 根节点入队

    while (!queues.empty()) {
        BSTNode<T>* curr = queues.front(); // 获取队头节点
        queues.pop();// 出队头节点
        printf("%d ", curr->data); // 输出当前节点值

        // 左子节点入队(先左后右)
        if (curr->left != NULL) {
            queues.push(curr->left);
        }
        // 右子节点入队
        if (curr->right != NULL) {
            queues.push(curr->right);
        }
    }
}

// 销毁整棵树(防止内存泄漏)
template <typename T>
void LinkedBSTree<T>::destroyTree(BSTNode<T>* node)
{
    if (node == nullptr) return;
    destroyTree(node->left);
    destroyTree(node->right);
    delete node;
}

//---------------实现公共成员函数---------------

// 获取root指针
template <typename T>
BSTNode<T>* LinkedBSTree<T>::getRoot()
{
    return root;
}

// 判断搜索树是否为空
template <typename T>
int LinkedBSTree<T>::isEmpty()
{
    return root == nullptr ? 1 : 0;
}

// 判断搜索树是否已满(链表实现永远不满,返回0)
template <typename T>
int LinkedBSTree<T>::isFull()
{
     return 0;
}

// 插入节点
template <typename T>
void LinkedBSTree<T>::insertNode(const T& val)
{
    //root = insertNode(root, val);// 插入节点(递归版本)
    root = insertNodeIter(root, val);// 插入节点(迭代版本)
}

// 删除节点
template <typename T>
void LinkedBSTree<T>::deleteNode(const T& val)
{
    //root = deleteNode(root, val);// 删除节点(递归版本)
    root = deleteNodeIter(root, val);// 删除节点(迭代版本)
}

// 查找节点
template <typename T>
bool LinkedBSTree<T>::searchNode(const T& val)
{
    //return searchNode(root,val);// 查找节点(递归版本)
    return searchNodeIter(root,val);// 查找节点(迭代版本)
}

// 前序遍历(根 → 左 → 右)
template <typename T>
void LinkedBSTree<T>::preOrder()
{
    preOrder(root);
}

// 中序遍历(左 → 根 → 右)→ 升序输出
template <typename T>
void LinkedBSTree<T>::inOrder()
{
    inOrder(root);
}

// 后序遍历(左 → 右 → 根)
template <typename T>
void LinkedBSTree<T>::postOrder()
{
    postOrder(root);
}

// 销毁整棵树(防止内存泄漏)
template <typename T>
void LinkedBSTree<T>::destroyTree()
{
    destroyTree(root);
    printf("\n===== 树内存已全部释放 =====\n");
}

// 显式实例化常用类型(避免链接错误,可选)
template class LinkedRBTree<int>;
template class LinkedRBTree<char>;
template class LinkedRBTree<float>;
template class LinkedBSTree<std::string>;
template class LinkedAVLTree<Student>; // 新增:显式实例化Student类型
template class LinkedAVLTree<StudentIndex>; // 新增:显式实例化StudentIndex类型

main.cpp 测试代码

#include "LinkedBSTree.h"
#include <iostream>
#include <string>

int main() {
    // ==================== 测试1:int类型BST搜索树 ====================
    LinkedBSTree<int> intTree;
    int intKeys[] = {10, 20, 30, 15, 25, 5, 8};
    int n = sizeof(intKeys)/sizeof(intKeys[0]);

    // 插入int节点
    std::cout << "=== Insert int keys: ";
    for (int i = 0; i < n; i++) {
        std::cout << intKeys[i] << " ";
        intTree.insertNode(intKeys[i]);
    }
    std::cout << "===" << std::endl;

    intTree.preOrder();

    // 查找测试
    int target = 31;
    if (intTree.searchNode(target)) {
        std::cout << "\nFound " << target << " in int tree!" << std::endl;
    }

    // 删除测试
    int deleteKey = 5;
    std::cout << "\n=== Delete key: " << deleteKey << " ===" << std::endl;
    intTree.deleteNode(deleteKey);
    // 前序遍历
    intTree.preOrder();

    // 销毁树(析构函数自动调用,此处显式调用演示)
    intTree.destroyTree();
    
    return 0;
}

六、注意事项

模板类型约束

  • 模板类型需支持</>/==运算符(内置类型如int/string默认支持,自定义类型需重载);
  • 自定义类型需重载<<运算符(遍历输出时使用)。

内存管理

  • 析构函数自动调用destroyTree(),无需手动释放,但手动调用也可;
  • 插入/删除时会自动更新节点数(qty),可扩展接口返回节点数。

重复值处理:代码中二叉搜索树不存储重复值(插入时直接返回),若需支持重复值,可修改插入逻辑(如按<=/>=处理)。

显式实例化:代码末尾的template class LinkedBSTree<int>;等显式实例化,避免链接错误,新增类型需补充显式实例化。

七、总结

二叉搜索树是最基础的有序二叉树结构,核心价值在于有序性高效的查找/插入/删除

本教程通过代码解析和实战示例,覆盖了BST的核心原理、关键操作实现和实际使用场景,掌握BST是学习高级平衡树(如AVL、红黑树)的基础,适用于需要高效有序数据操作的场景(如小型索引、有序集合管理)。


返回顶部