C++ 简单实现一棵二叉搜索树(递归版本与非递归版本)附代码

二叉搜索树(Binary Search Tree, 简称BST)是一种非常常用的数据结构,它是一种节点具有左右子树,它的每个节点都满足左子树所有节点小于当前节点,右子树所有节点大于当前节点。

在这之前先介绍一下模板K与模板V:

模板K:记录当前节点的值,可以帮助我们方便地进行节点的查找、插入和删除等操作,因为我们可以通过比较节点的键值来确定需要访问的子树,这个有点类似于数组中的下标。

模板V:我们可以将“V模板”应用到节点的值域上,存储数据。使用“V模板”可以帮助我们方便地对节点的值进行读取和修改,也可以实现一些高级操作,例如计算BST中各个节点之间的关系等。

一、递归版本

#include<iostream>
#include<string>
using namespace std;

template<class K, class V>
class BSTNode {
public:
    K _key;
    V _value;
    BSTNode* _left;
    BSTNode* _right;

    BSTNode(K key, V value) : _key(key), _value(value), _left(nullptr), _right(nullptr) {}
};

template<class K, class V>
class BSTree
{
private:
    BSTNode<K, V>* _root;

public:
    BSTree() : _root(nullptr) {}// 构造函数

    void insert(K key, V value)// 插入数据
    {
        _root = insertNode(_root, key, value);
    }

    V* find(K key) {// 找到节点key存储的数据
        BSTNode<K, V>* node = findNode(_root, key);
        if (node != nullptr) {
            return &(node->_value);
        }
        else {
            return nullptr;
        }
    }

    void InOrder()// 中序遍历,会按key从小到大输出数据
    {
        _InOrder(_root);
        cout << endl;
    }

    void remove(K key) {// 删除节点key
        _root = removeNode(_root, key);
    }

    void change(K key,V value)
    {
        BSTNode<K, V>* tmp = findNode(_root, key);
        if (tmp != nullptr)
        {
            tmp->_value = value;
        }
    }

private:
    // 辅助函数
    void _InOrder(BSTNode<K, V>* root)
    {
        if (root == nullptr)
            return;
        _InOrder(root->_left);
        cout << root->_key << ":" << root->_value << endl;
        _InOrder(root->_right);
    }


    BSTNode<K, V>* insertNode(BSTNode<K, V>* node, K key, V value) {
        if (node == nullptr) {
            return new BSTNode<K, V>(key, value);
        }

        if (key < node->_key) {
            node->_left = insertNode(node->_left, key, value);
        }
        else if (key > node->_key) {
            node->_right = insertNode(node->_right, key, value);
        }
        else {
            node->_value = value;  // 节点已经存在,更新其value值
        }

        return node;
    }

    BSTNode<K, V>* findNode(BSTNode<K, V>* node, K key) {
        if (node == nullptr || node->_key == key) {
            return node;
        }

        if (key < node->_key) {
            return findNode(node->_left, key);
        }
        else {
            return findNode(node->_right, key);
        }
    }

    BSTNode<K, V>* removeNode(BSTNode<K, V>* node, K key) {
        if (node == nullptr) {
            return nullptr;
        }

        if (key < node->_key) {
            node->_left = removeNode(node->_left, key);
        }
        else if (key > node->_key) {
            node->_right = removeNode(node->_right, key);
        }
        else {
            // 找到了要删除的节点,根据其子节点情况进行删除
            if (node->_left == nullptr && node->_right == nullptr) {
                // 情况1:要删除的节点没有子节点
                delete node;
                node = nullptr;
            }
            else if (node->_left == nullptr) {
                // 情况2A:要删除的节点只有一个右子节点
                BSTNode<K, V>* temp = node;
                node = node->_right;
                delete temp;
            }
            else if (node->_right == nullptr) {
                // 情况2B:要删除的节点只有一个左子节点
                BSTNode<K, V>* temp = node;
                node = node->_left;
                delete temp;
            }
            else {
                // 情况3:要删除的节点有两个子节点,需要找到它的中序后继。
                // 可以找到该节点左子树的最大值和右子树的最小值来作为它的中序后继,
                // 这里我们选择找它的右子树的最小值。
                BSTNode<K, V>* temp = findMinNode(node->_right);
                node->_key = temp->_key;
                node->_value = temp->_value;
                node->_right = removeNode(node->_right, temp->_key);//在node右边寻找要被删除的key然后删除,递归返回
            }
        }

        return node;
    }

    BSTNode<K, V>* findMinNode(BSTNode<K, V>* node) {
        while (node->_left != nullptr) {
            node = node->_left;
        }

        return node;
    }
};



int main()
{
    BSTree<int, string> bst;
    bst.insert(5, "apple");
    bst.insert(3, "banana");
    bst.insert(4, "grape");
    bst.insert(1, "banana");
    bst.insert(7, "grape");
    bst.insert(8, "banana");
    bst.insert(6, "grape");
    bst.insert(0, "apple");
    bst.insert(9, "apple");

    //bst.InOrder();

    bst.remove(5);
    bst.InOrder();

    cout<<*bst.find(7)<<endl;
    bst.change(7, "apple");
    bst.InOrder();

    return 0;
}

1.key的关系图与测试结果

key的关系图:

看一下测试结果:

二、非递归版本

#include<string>
#include<iostream>
using namespace std;

template<class K, class V>
struct BSTreeNode  //Binary Search Tree
{
    BSTreeNode<K, V>* _left;
    BSTreeNode<K, V>* _right;

    K _key;
    V _value;

    BSTreeNode(const K& key, const V& value)
        :_left(nullptr)
        , _right(nullptr)
        , _key(key)
        , _value(value)
    {}
};

template<class K, class V>
class BSTree
{
    typedef BSTreeNode<K, V> Node;
public:
    bool Insert(const K& key, const V& value);
    Node* Find(const K& key);
    bool Remove(const K& key);
    void Change(K key, V newvalue);
    void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }
private:
    void _InOrder(Node* root)
    {
        if (root == nullptr)
            return;
        _InOrder(root->_left);
        cout << root->_key << ":" << root->_value << endl;
        _InOrder(root->_right);
    }
    Node* _root = nullptr;
};


template<class K, class V>
bool BSTree<K, V>::Insert(const K& key, const V& value)
{
    // 1.根节点为空
    if (_root == nullptr)
    {
        _root = new Node(key, value);
        return true;
    }

    // 2.根节点不为空
    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
        {
            // 当key存在时,我们不更新其值而是报错
            return false;
        }
    }

    // 3.parent和cur已经走到了合适的位置,插入节点后链接起来
    cur = new Node(key, value);
    if (parent->_key < key)
    {
        parent->_right = cur;
    }
    else
    {
        parent->_left = cur;
    }

    return true;
}

template<class K, class V>
bool BSTree<K, V>::Remove(const K& key)
{
    Node* parent = nullptr;
    Node* cur = _root;

    //1.查找要被删除的_key
    while (cur)
    {
        if (cur->_key < key)
        {
            parent = cur;
            cur = cur->_right;
        }
        else if (cur->_key > key)
        {
            parent = cur;
            cur = cur->_left;
        }
        else// 已经找到_key
        {
            // 1A.左为空
            if (cur->_left == nullptr)
            {
                if (cur == _root)
                {
                    _root = cur->_right;
                }
                else
                {
                    if (parent->_right == cur)
                        parent->_right = cur->_right;
                    else
                        parent->_left = cur->_right;
                }

                delete cur;
            }
            // 1B.右为空
            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;
                }

                delete cur;
            }
            // 1C.左右都不为空
            else
            {
                // 可以用cur右树最小的_key或左树最大的_key来替代它,这里我们选择用右树最小的_key
                Node* rightMinParent = cur;
                Node* rightMin = cur->_right;
                while (rightMin->_left)
                {
                    rightMinParent = rightMin;
                    rightMin = rightMin->_left;
                }
                
                // 节点替换
                cur->_key = rightMin->_key;
                cur->_value = rightMin->_value;

                // 考虑到被删除的节点可能存在有右子树,我们还需要链接起来它的右子树
                if (rightMin == rightMinParent->_left)
                    rightMinParent->_left = rightMin->_right;
                else
                    rightMinParent->_right = rightMin->_right;

                delete rightMin;
            }
            return true;
        }
    }

    //2._key不存在,报错
    return false;
}

template<class K, class V>
BSTreeNode<K, V>* BSTree<K, V>::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 cur;
        }
    }

    return nullptr;
}


template<class K, class V>
void BSTree<K, V>::Change(K key, V newvalue) 
{
    Node* cur = Find(key);
    if (cur != nullptr)
    {
        cur->_value = newvalue;
    }
}

int main()
{
    BSTree<int,string> bst;

    bst.Insert(5, "apple");
    bst.Insert(3, "banana");
    bst.Insert(4, "grape");
    bst.Insert(1, "banana");
    bst.Insert(7, "grape");
    bst.Insert(8, "banana");
    bst.Insert(6, "grape");
    bst.Insert(0, "apple");
    bst.Insert(9, "apple");

    bst.InOrder();

    return 0;
}

_key关系图(同上递归版本):

1.测试结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值