C++ 搜索二叉树(BST)详解:实现与应用

发布于:2025-06-09 ⋅ 阅读:(14) ⋅ 点赞:(0)

目录

一、搜索二叉树基础概念

二、BST节点结构实现

三、核心操作实现

1. 插入操作

2. 查找操作

3. 删除操作

四、BST的高级功能

1. 中序遍历

2. 拷贝构造函数和赋值运算符

3. 析构函数

五、键值对BST的实现

1. 字典应用

2. 统计应用

总结


搜索二叉树(Binary Search Tree, BST)是一种重要的数据结构,它结合了链表的灵活性和数组的快速查找优势。本文将详细介绍C++中搜索二叉树的实现原理、核心操作以及实际应用场景。

一、搜索二叉树基础概念

搜索二叉树是一种特殊的二叉树,它具有以下性质:

  • 每个节点包含一个键值(key)
  • 左子树所有节点的键值小于根节点的键值
  • 右子树所有节点的键值大于根节点的键值
  • 左右子树也分别是搜索二叉树

这种结构使得查找、插入和删除操作的平均时间复杂度为O(log n)。

二、BST节点结构实现

我们首先定义BST的节点结构:

template<class K>
class BSTreeNode {
public:
    K _key;                 // 节点存储的键值
    BSTreeNode<K>* _left;    // 左子节点指针
    BSTreeNode<K>* _right;   // 右子节点指针
    
    BSTreeNode(const K& key)
        :_key(key)
        ,_left(nullptr)
        ,_right(nullptr)
    {}
};

三、核心操作实现

1. 插入操作

非递归实现:

bool Insert(const K& key) {
    if (_root == nullptr) {
        _root = new Node(key);
        return true;
    }
    
    Node* parent = nullptr;
    Node* cur = _root;
    
    while (cur) {
        if (cur->_key < key) {
            parent = cur;
            cur = cur->_right;
        }
        else if (cur->_key > key) {
            parent = cur;
            cur = cur->_left;
        }
        else {
            return false; // 键值已存在
        }
    }
    
    cur = new Node(key);
    if (parent->_key < key) {
        parent->_right = cur;
    }
    else {
        parent->_left = cur;
    }
    return true;
}

递归实现:

bool _InsertR(Node*& root, const K& key) {
    if (root == nullptr) {
        root = new Node(key);
        return true;
    }
    if (root->_key < key) {
        return _InsertR(root->_right, key);
    }
    else if (root->_key > key) {
        return _InsertR(root->_left, key);
    }
    else {
        return false; // 键值已存在
    }
}

2. 查找操作

非递归实现:

bool Find(const K& key) {
    Node* cur = _root;
    while (cur) {
        if (cur->_key < key) {
            cur = cur->_right;
        }
        else if (cur->_key > key) {
            cur = cur->_left;
        }
        else {
            return true;
        }
    }
    return false;
}

递归实现:

bool _FindR(Node* root, const K& key) {
    if (root == nullptr) {
        return false;
    }
    if (root->_key < key) {
        return _FindR(root->_right, key);
    }
    else if (root->_key > key) {
        return _FindR(root->_left, key);
    }
    else {
        return true;
    }
}

3. 删除操作

删除操作较为复杂,需要考虑三种情况:

  1. 删除叶子节点
  2. 删除只有左子树或右子树的节点
  3. 删除有两个子树的节点

非递归实现:

bool Erase(const K& key) {
    Node* cur = _root;
    Node* parent = cur;
    
    while (cur) {
        if (cur->_key < key) {
            parent = cur;
            cur = cur->_right;
        }
        else if (cur->_key > key) {
            parent = cur;
            cur = cur->_left;
        }
        else {
            // 找到要删除的节点
            if (cur->_left == nullptr) {
                // 左子树为空的情况
                if (cur == _root) {
                    _root = cur->_right;
                }
                else {
                    if (parent->_right == cur) {
                        parent->_right = cur->_right;
                    }
                    else {
                        parent->_left = cur->_right;
                    }
                }
            }
            else if (cur->_right == nullptr) {
                // 右子树为空的情况
                if (cur == _root) {
                    _root = cur->_left;
                }
                else {
                    if (parent->_left == cur) {
                        parent->_left = cur->_left;
                    }
                    else {
                        parent->_right = cur->_left;
                    }
                }
            }
            else {
                // 左右子树都不为空的情况
                Node* parent = cur;
                Node* leftMax = cur->_left;
                while (leftMax->_right) {
                    parent = leftMax;
                    leftMax = leftMax->_right;
                }
                swap(cur->_key, leftMax->_key);
                if (parent->_left == leftMax) {
                    parent->_left = leftMax->_left;
                }
                else {
                    parent->_right = leftMax->_left;
                }
                cur = leftMax;
            }
            delete cur;
            return true;
        }
    }
    return false;
}

递归实现:

bool _EraseR(Node*& root, const K& key) {
    if (root == nullptr) {
        return false;
    }
    if (root->_key < key) {
        return _EraseR(root->_right, key);
    }
    else if (root->_key > key) {
        return _EraseR(root->_left, key);
    }
    else {
        Node* del = root;
        if (root->_left == nullptr) {
            root = root->_right;
        }
        else if (root->_right == nullptr) {
            root = root->_left;
        }
        else {
            Node* leftMax = root->_left;
            while (leftMax->_right) {
                leftMax = leftMax->_right;
            }
            swap(root->_key, leftMax->_key);
            return _EraseR(root->_left, key);
        }
        delete del;
        return true;
    }
}

四、BST的高级功能

1. 中序遍历

中序遍历BST会得到一个有序的序列:

void _InOrder(Node* root) {
    if (root == nullptr) {
        return;
    }
    _InOrder(root->_left);
    cout << root->_key << " ";
    _InOrder(root->_right);
}

2. 拷贝构造函数和赋值运算符

BSTree(const BSTree<K>& t) {
    _root = Copy(t._root);
}

BSTree<K>& operator=(BSTree<K> t) {
    swap(_root, t._root);
    return *this;
}

Node* Copy(Node* root) {
    if (root == nullptr) return nullptr;
    Node* copyroot = new Node(root->_key);
    copyroot->_left = Copy(root->_left);
    copyroot->_right = Copy(root->_right);
    return copyroot;
}

3. 析构函数

~BSTree() {
    Destroy(_root);
}

void Destroy(Node*& root) {
    if (root == nullptr) return;
    Destroy(root->_left);
    Destroy(root->_right);
    delete root;
    root = nullptr;
}

五、键值对BST的实现

我们可以扩展BST以支持键值对存储:

template<class K, class V>
class BSTreeNode {
public:
    K _key;
    V _value;
    BSTreeNode<K,V>* _left;
    BSTreeNode<K,V>* _right;
    
    BSTreeNode(const K& key, const V& value)
        :_key(key)
        ,_value(value)
        ,_left(nullptr)
        ,_right(nullptr)
    {}
};

这种结构非常适合实现字典或统计应用:

1. 字典应用

void TestBSTree1() {
    BSTree<string, string> dict;
    dict.InsertR("insert", "插入");
    dict.InsertR("sort", "排序");
    dict.InsertR("right", "右边");
    dict.InsertR("date", "日期");
    
    string str;
    while (cin >> str) {
        auto ret = dict.FindR(str);
        if (ret) {
            cout << ret->_value << endl;
        }
        else {
            cout << "无此单词" << endl;
        }
    }
}

2. 统计应用

void TestBSTree2() {
    string arr[] = { "苹果","西瓜","西瓜","西瓜","香蕉","苹果", "苹果", "苹果", "苹果", "苹果" };
    BSTree<string, int> countTree;
    
    for (auto& str : arr) {
        auto ret = countTree.FindR(str);
        if (ret == nullptr) {
            countTree.InsertR(str, 1);
        }
        else {
            ret->_value++;
        }
    }
    countTree.InOrder();
}

总结

搜索二叉树是数据结构与算法中的重要内容,掌握它的实现原理和应用场景对于提升编程能力非常有帮助。本文详细介绍了C++中BST的实现方法,包括基本操作和高级功能,并展示了它在实际中的应用。理解这些内容将为学习更复杂的数据结构打下坚实基础。

希望这篇博客对你理解和使用搜索二叉树有所帮助!如果有任何问题,欢迎在评论区留言讨论。


网站公告

今日签到

点亮在社区的每一天
去签到