C++必修:set与map的模拟实现

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C++学习
贝蒂的主页:Betty’s blog

1. set与map的结构

我们知道STL中的setmap底层就是一颗红黑树,接下来我们模拟setmap肯定需要一颗红黑树作为我们的成员变量,如果在此之前并不了解红黑树,可以参考——红黑树

1.1 set的结构

我们知道set其实就是K模型,所以set容器对红黑树的封装如下:

template<class K>
class set
{
public:
    //成员函数
private:
    RBTree<K, K> _t;
};

1.2 map的结构

我们也知道map其实就是KV模型,所以map容器对红黑树的封装如下:

template<class K, class V>
class map
{
public:
    //成员函数
private:
    RBTree<K, pair<const K, V>> _t;
};

其中为了防止pairK被修改,我们可以加上const修饰。其实set中的K同样不能修改,但是我们可以在其迭代器实现中进行统一处理。

2. 改造红黑树

其中红黑树的接口如下:

template<class K, class T>
class RBTree

第一个参数代表key,第二个参数为key或者keyvalue形成的键值对。对于set来说,第一个模版参数与第二个模版参数相同;对于map来说,第一个参数为key,第二个参数为keyvalue形成的键值对。

2.1 改造红黑树的节点

其中红黑树的节点类型就是模版参数T,所以我们对节点改造如下:

enum _col
{
	RED,//红色
	BLACK//黑色
};
template<class T>
struct RBNode
{
	RBNode(const T& value = T(), _col col = RED)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _value(value)
		, _col(col)//默认为红节点
	{}
	RBNode<T>* _left;//左子树
	RBNode<T>* _right;//右子树
	RBNode<T>* _parent;//父节点
	T _value;//键值
	_col _col;//颜色
};

2.2 改造红黑树

2.2.1 增加仿函数

首先为了方便不同类型之间的比较,所以我们需要定义一个仿函数,而不同类型需要的仿函数可能是不同的。所以我们需要模版参数显示传参:

template<class K>
class set
{
    //增加仿函数
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
public:
	//成员函数
private:
	RBTree<K, K, SetKeyOfT> _t;
};
template<class K, class V>
class map
{
    //仿函数
    struct MapKeyOfT
    {
        const K& operator()(const pair<K, V>& kv)
        {
            return kv.first;
        }
    };
public:
    //成员函数
private:
    RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};

然后我们将所有需要比较key的函数利用仿函数进行替换,我们以Find为例。

iterator Find(const K& val)
{
    //使用仿函数
    KeyOfT kot;
    Node* cur = _root;
    while (cur)
    {
        if (kot(cur->_value) > val)
        {
            //左子树中查找
            cur = cur->_left;
        }
        else if (kot(cur->_value) < val)
        {
            //右子树中查找
            cur = cur->_right;
        }
        else
        {
            //找到了
            return iterator(cur);
        }
    }
    //找不到返回end()
    return end();
}
2.2.2 改造插入

首先我们改造Insert函数,除了比较大于需要用仿函数替换以外,我们还需要对返回值进行改造:返回值是一个pair,第一个参数是一个迭代器,第二个参数是一个bool

  • 若待插入元素的键值key在容器当中不存在,则insert函数插入成功,并返回插入后元素的迭代器和true
  • 若待插入元素的键值key在容器当中已经存在,则insert函数插入失败,并返回容器当中键值为key的元素的迭代器和false
pair<iterator, bool> Insert(const T& data)
{
    //情况一:如果是根节点
    if (_root == nullptr)
    {
        _root = new Node(data);
        _root->_col = BLACK;
        return make_pair(iterator(_root),true);
    }
    KeyOfT kot;
    Node* parent = nullptr;
    Node* cur = _root;
    while (cur)
    {
        if (kot(cur->_value) < kot(data))
        {
            parent = cur;
            cur = cur->_right;
        }
        else if (kot(cur->_value) > kot(data))
        {
            parent = cur;
            cur = cur->_left;
        }
        else
        {
            return make_pair(iterator(cur), false);
        }
    }
    //找到插入位置
    cur = new Node(data);
    Node* newnode = cur;
    if (kot(parent->_value) < kot(data))
    {
        parent->_right = cur;
    }
    else
    {
        parent->_left = cur;
    }
    cur->_parent = parent;
    while (parent && parent->_col == RED)
    {
        Node* grandfather = parent->_parent;
        if (parent == grandfather->_left)
        {
            Node* uncle = grandfather->_right;
            //情况三:如果叔叔存在且为红
            if (uncle && uncle->_col == RED)
            {
                parent->_col = uncle->_col = BLACK;
                grandfather->_col = RED;
                cur = grandfather;
                parent = cur->_parent;
            }
            else
            {
                //情况四:叔叔不存在/存在且为黑,且cur在parent的左侧
                if (cur == parent->_left)
                {
                    //     g  
                    //   p   u
                    // c 
                    RotateR(grandfather);
                    parent->_col = BLACK;
                    grandfather->_col = RED;
                }
                else//情况五:叔叔不存在 / 存在且为黑,cur在parent的右侧
                {
                    //     g
                    //   p   u
                    //     c
                    RotateLR(grandfather);
                    cur->_col = BLACK;
                    grandfather->_col = RED;
                }
                //这时该子树的根节点变为黑色,不需要继续调整
                break;
            }
        }
        else
        {
            Node* uncle = grandfather->_left;
            //情况三:如果叔叔存在且为红
            if (uncle && uncle->_col == RED)
            {
                parent->_col = uncle->_col = BLACK;
                grandfather->_col = RED;
                //继续调整
                cur = grandfather;
                parent = cur->_parent;
            }
            else
            {
                //情况四:叔叔不存在/存在且为黑,且cur在parent的左侧
                if (cur == parent->_right)
                {
                    //    g
                    //  u   p
                    //        c
                    RotateL(grandfather);
                    parent->_col = BLACK;
                    grandfather->_col = RED;
                }
                else // 情况五:叔叔不存在 / 存在且为黑,cur在parent的右侧
                {
                    //    g
                    //  u   p
                    //    c
                    RotateRL(grandfather);
                    cur->_col = BLACK;
                    grandfather->_col = RED;
                }
                //这时该子树的根节点变为黑色,不需要继续调整
                break;
            }
        }

    }
    //防止情况三改到根节点变为红色
    _root->_col = BLACK;
    return make_pair(iterator(newnode), true);
}
2.2.3 改造删除

改造删除需要注意两点,一点就是我们删除逻辑中复用了查找函数,而查找返回的是是一个迭代器,我们需要的是对应节点的指针,所以我们需要在迭代器中提供一个通过迭代器返回对应指针的函数。

//(一)找到删除节点
iterator it = Find(key);
Node* cur = it.getNode();

第二点就是对于map的键值中的K是被const修饰的无法修改,而在红黑树删除中如果左右孩子都不为空需要采用伪删除法,这时需要对节点的值就性覆盖。为了解决这个问题,我们可以重新创造一个节点对红黑树进行重新链接,再把将原节点删除。

else //待删除结点的左右子树均不为空
{
    //替换法删除
    //寻找待删除结点右子树当中key值最小的结点作为实际删除结点
    Node* minParent = cur;
    Node* minRight = cur->_right;
    while (minRight->_left)
    {
        minParent = minRight;
        minRight = minRight->_left;
    }
    // 原本直接可以赋值
    // cur->_value = minRight->_value 
    //将待删除结点的键值改为minRight的键值
    Node* newnode = new Node(minRight->_value,cur->_col);
    Node* parent = cur->_parent;
    //重新链接祖父孙三代节点关系
    cur->_left->_parent = newnode;
    cur->_right->_parent = newnode;
    if (parent)
    {
        if (parent->_left == cur)
        {
            parent->_left = newnode;
        }
        else
        {
            parent->_right = newnode;
        }
    }
    else
    {
        //如果是根节点
        _root = newnode;
    }
    newnode->_parent = parent;
    newnode->_left = cur->_left;
    newnode->_right = cur->_right;
    //如果minParent是cur
    if (minParent == cur)
    {
        minParent = newnode;
    }
    delete cur;
    delParent = minParent; //标记实际删除的父节点
    delCur = minRight; //标记实际删除的结点
}

3. 迭代器

因为map/set底层为红黑树,节点与节点之间并不连续,所以迭代器也肯定需要进行封装。为了同时支持const迭代器与普通迭代器,我们需要三个模版参数,第一个模版参数T代表数据存储类型,第二个模版参数Ref代表存储类型的引用,第三个模版参数Ptr代表存储类型的指针。然后我们重载如++--等常见操作符。

template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
    typedef RBNode<T> Node;
    typedef __RBTreeIterator<T, Ref, Ptr> Self;
    Node* _node;
    //构造
    __RBTreeIterator(Node* node)
        :_node(node)
    {}
    Ref operator*()
    {
        return _node->_value;
    }
    Ptr operator->()
    {
        return &_node->_value;
    }
    //判断两个正向迭代器是否不同
    bool operator!=(const Self& s) const
    {
        return _node != s._node;
    }
    //判断两个正向迭代器是否相同
    bool operator==(const Self& s) const
    {
        return _node == s._node;
    }
    Node* getNode()
    {
        return _node;
    }
};

接下来我们需要在红黑树中编写常见的迭代器函数,因为我们的迭代器是按中序遍历的,所以begin()就是红黑树的最左节点,而end()我们可以先将其设置nullptr
6ca2a542a6344df346352dd0f305613a.png

typedef __RBTreeIterator<T, T&, T*> iterator;//普通迭代器
typedef __RBTreeIterator<T, const T&, const T*> const_iterator;//const迭代器
//最左节点
iterator begin()
{
    Node* cur = _root;
    while (cur && cur->_left)
    {
        cur = cur->_left;
    }
    return iterator(cur);
}
iterator end()
{
    return iterator(nullptr);
}
//const版本begin和end
const_iterator begin()const
{
    Node* cur = _root;
    while (cur && cur->_left)
    {
        cur = cur->_left;
    }
    return const_iterator(cur);
}

const_iterator end()const
{
    return const_iterator(nullptr);
}

接下来我们再重载迭代器的++--。其中++的逻辑为找到中序遍历的下一个节点,其遍历逻辑为:

  • 如果当前结点的右子树不为空,则++操作后应该找到其右子树当中的最左结点。
  • 如果当前结点的右子树为空,则++操作后应该往上找到孩子不在父亲右的祖先。

--的逻辑恰好相反:

  • 如果当前结点的左子树不为空,则--操作后应该找到其左子树当中的最右结点。
  • 如果当前结点的左子树为空,则--操作后应该往上找到孩子不在父亲左的祖先。
 //前置++
 Self& operator++()
 {
     //如果右子树不为空
     if (_node->_right)
     {
         //寻找该结点右子树当中的最左结点
         Node* left = _node->_right;
         while (left->_left)
         {
             left = left->_left;
         }
         _node = left;
     }
     else
     {
         Node* cur = _node;
         Node* parent = cur->_parent;
         //寻找孩子不在右的祖先
         while (parent && cur == parent->_right)
         {
             cur = parent;
             parent = cur->_parent;
         }
         _node = parent;
     }
     return *this;
 }
 //前置--
 Self& operator--()
 {
     if (_node->_left) //结点的左子树不为空
     {
         //寻找该结点左子树当中的最右结点
         Node* right = _node->_left;
         while (right->_right)
         {
             right = right->_right;
         }
         _node = right;
     }
     else
     {
         //寻找孩子不在父亲左的祖先
         Node* cur = _node;
         Node* parent = cur->_parent;
         while (parent && cur == parent->_left)
         {
             cur = parent;
             parent = parent->_parent;
         }
         _node = parent;
     }
     return *this;
 }

然后我们可以在set/map中增加相应的迭代器,其中需要注意的是set中的迭代器为了防止key被修改,将普通迭代器也设为const迭代器。但这就引发了一个问题就是:普通迭代器调用仍是红黑树的普通迭代器,返回普通迭代器并不与const迭代器兼容,为了解决这个问题我们仍需要在迭代器中重载一个普通迭代器初始化const迭代器的构造函数。

//普通迭代器构造const迭代器
__RBTreeIterator(const __RBTreeIterator<T,T&,T*>& it)
    :_node(it._node)
{}

最后我们直接再复用红黑树的接口就可以实现set/map中的成员函数:

template<class K>
class set
{
    struct SetKeyOfT
    {
        const K& operator()(const K& key)
        {
            return key;
        }
    };
public:
    //typename声明是一个类型而不是静态变量
    typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
    typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
    //成员函数
    iterator begin()
    {
        return _t.begin();
    }
    iterator end()
    {
        return _t.end();
    }
    const_iterator begin() const
    {
        return _t.begin();
    }

    const_iterator end() const
    {
        return _t.end();
    }
    pair<iterator, bool> insert(const K& key)
    {
        return _t.Insert(key);
    }
    //删除函数
    void erase(const K& key)
    {
        _t.Erase(key);
    }
    //查找函数
    iterator find(const K& key)
    {
        return _t.Find(key);
    }
private:
    RBTree<K, K, SetKeyOfT> _t;
};
template<class K, class V>
class map
{
	//仿函数
	struct MapKeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};
public:
	//typename声明是一个类型而不是静态变量
	typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator; 
	typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;
	//成员函数
	iterator begin()
	{
		return _t.begin();
	}
	iterator end()
	{
		return _t.end();
	}
	const_iterator begin() const
	{
		return _t.begin();
	}
	const_iterator end() const
	{
		return _t.end();
	}
	pair<iterator, bool> insert(const pair<K,V>& key)
	{
		return _t.Insert(key);
	}
	//删除函数
	void erase(const K& key)
	{
		_t.Erase(key);
	}
	//查找函数
	iterator find(const K& key)
	{
		return _t.Find(key);
	}
	//[]运算符重载
	V& operator[](const K& key)
	{
		pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
		return ret.first->second;
	}
private:
	RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};

其实我们设计的迭代器是有一个问题的,那就是end()如果进行--操作按理来说应该是最后一个节点,但是我们设置为nullptr就无法实现这一点。而在STL库中是这样解决这个问题的:
4960816bc62a53917de6c691ee7526a5 (1).png
对根节点增加一个头节点,让这个头节点的左指针指向最左节点,右指针指向最右节点。然后让用头节点的左节点构造begin(),头节点本身构造end(),这样就能实现--之后指向最右节点。但这样一来我们所有的逻辑都需要改变,而我们原本的逻辑除了这点无法满足外,并没有太大影响,所以最后就不在实现这种版本了。

思考题:为什么需要第一个模版参数K,不是可以通过第二个模版参数获取K吗?

对于set来说,直接使用第二个模版参数时没有任何问题的,但是对于map来说,查找与删除等操作是以key作为查找基准的,虽然说可以通过.first获取对应的key元素,但是由于setmap封装的是同一颗红黑树,set中的key并不存在像.first这样的操作。所以为了使setmap能封装同一棵红黑树,最好增加一个模版参数获取对应的key

4. 源码

4.1 RBTree.h

#pragma once
#include<utility>
enum _col
{
    RED,//红色
    BLACK//黑色
};
template<class T>
struct RBNode
{
    RBNode(const T& value = T(), _col col = RED)
        :_left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
        , _value(value)
        , _col(col)//默认为红节点
    {}
    RBNode<T>* _left;//左子树
    RBNode<T>* _right;//右子树
    RBNode<T>* _parent;//父节点
    T _value;//键值
    _col _col;//颜色
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
    typedef RBNode<T> Node;
    typedef __RBTreeIterator<T, Ref, Ptr> Self;
    Node* _node;
    //构造
    __RBTreeIterator(Node* node)
        :_node(node)
    {}
    //普通迭代器构造const迭代器
    __RBTreeIterator(const __RBTreeIterator<T,T&,T*>& it)
        :_node(it._node)
    {}
    Ref operator*()
    {
        return _node->_value;
    }
    Ptr operator->()
    {
        return &_node->_value;
    }
    //判断两个正向迭代器是否不同
    bool operator!=(const Self& s) const
    {
        return _node != s._node;
    }
    //判断两个正向迭代器是否相同
    bool operator==(const Self& s) const
    {
        return _node == s._node;
    }
    //前置++
    Self& operator++()
    {
        //如果右子树不为空
        if (_node->_right)
        {
            //寻找该结点右子树当中的最左结点
            Node* left = _node->_right;
            while (left->_left)
            {
                left = left->_left;
            }
            _node = left;
        }
        else
        {
            Node* cur = _node;
            Node* parent = cur->_parent;
            //寻找孩子不在右的祖先
            while (parent && cur == parent->_right)
            {
                cur = parent;
                parent = cur->_parent;
            }
            _node = parent;
        }
        return *this;
    }
    //前置--
    Self& operator--()
    {
        if (_node->_left) //结点的左子树不为空
        {
            //寻找该结点左子树当中的最右结点
            Node* right = _node->_left;
            while (right->_right)
            {
                right = right->_right;
            }
            _node = right;
        }
        else
        {
            //寻找孩子不在父亲左的祖先
            Node* cur = _node;
            Node* parent = cur->_parent;
            while (parent && cur == parent->_left)
            {
                cur = parent;
                parent = parent->_parent;
            }
            _node = parent;
        }
        return *this;
    }
    Node* getNode()
    {
        return _node;
    }
};
template<class K, class T, class KeyOfT>
class RBTree
{
    typedef RBNode<T> Node;
public:
    typedef __RBTreeIterator<T, T&, T*> iterator;//普通迭代器
    typedef __RBTreeIterator<T, const T&, const T*> const_iterator;//const迭代器
    //最左节点
    iterator begin()
    {
        Node* cur = _root;
        while (cur && cur->_left)
        {
            cur = cur->_left;
        }
        return iterator(cur);
    }
    iterator end()
    {
        return iterator(nullptr);
    }
    //const版本begin和end
    const_iterator begin()const
    {
        Node* cur = _root;
        while (cur && cur->_left)
        {
            cur = cur->_left;
        }
        return const_iterator(cur);
    }

    const_iterator end()const
    {
        return const_iterator(nullptr);
    }
    RBTree()
    {}
    RBTree(const RBTree<K, T, KeyOfT>& t)
    {
        _root = copy(t._root);
    }
    RBTree<K, T, KeyOfT> operator =(const RBTree<K, T, KeyOfT> t)
    {
        this->swap(_root, t._root);
        return *this;
    }
    pair<iterator, bool> Insert(const T& data)
    {
        //情况一:如果是根节点
        if (_root == nullptr)
        {
            _root = new Node(data);
            _root->_col = BLACK;
            return make_pair(iterator(_root),true);
        }
        KeyOfT kot;
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (kot(cur->_value) < kot(data))
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (kot(cur->_value) > kot(data))
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return make_pair(iterator(cur), false);
            }
        }
        //找到插入位置
        cur = new Node(data);
        Node* newnode = cur;
        if (kot(parent->_value) < kot(data))
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }
        cur->_parent = parent;
        while (parent && parent->_col == RED)
        {
            Node* grandfather = parent->_parent;
            if (parent == grandfather->_left)
            {
                Node* uncle = grandfather->_right;
                //情况三:如果叔叔存在且为红
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    cur = grandfather;
                    parent = cur->_parent;
                }
                else
                {
                    //情况四:叔叔不存在/存在且为黑,且cur在parent的左侧
                    if (cur == parent->_left)
                    {
                        //     g  
                        //   p   u
                        // c 
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else//情况五:叔叔不存在 / 存在且为黑,cur在parent的右侧
                    {
                        //     g
                        //   p   u
                        //     c
                        RotateLR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    //这时该子树的根节点变为黑色,不需要继续调整
                    break;
                }
            }
            else
            {
                Node* uncle = grandfather->_left;
                //情况三:如果叔叔存在且为红
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    //继续调整
                    cur = grandfather;
                    parent = cur->_parent;
                }
                else
                {
                    //情况四:叔叔不存在/存在且为黑,且cur在parent的左侧
                    if (cur == parent->_right)
                    {
                        //    g
                        //  u   p
                        //        c
                        RotateL(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else // 情况五:叔叔不存在 / 存在且为黑,cur在parent的右侧
                    {
                        //    g
                        //  u   p
                        //    c
                        RotateRL(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    //这时该子树的根节点变为黑色,不需要继续调整
                    break;
                }
            }

        }
        //防止情况三改到根节点变为红色
        _root->_col = BLACK;
        return make_pair(iterator(newnode), true);
    }
    void RotateR(Node* parent)
    {
        Node* cur = parent;
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left = subLR;
        if (subLR)
            subLR->_parent = parent;
        subL->_right = parent;
        Node* ppNode = parent->_parent;
        parent->_parent = subL;
        if (parent == _root)
        {
            _root = subL;
            _root->_parent = nullptr;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subL;
            }
            else
            {
                ppNode->_right = subL;
            }
            subL->_parent = ppNode;
        }
    }
    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        parent->_right = subRL;
        if (subRL)
            subRL->_parent = parent;

        subR->_left = parent;
        Node* ppNode = parent->_parent;

        parent->_parent = subR;

        if (parent == _root)
        {
            _root = subR;
            _root->_parent = nullptr;
        }
        else
        {
            if (ppNode->_right == parent)
            {
                ppNode->_right = subR;
            }
            else
            {
                ppNode->_left = subR;
            }
            subR->_parent = ppNode;
        }
    }
    void RotateLR(Node* parent)
    {
        RotateL(parent->_left);
        RotateR(parent);
    }
    void RotateRL(Node* parent)
    {
        RotateR(parent->_right);
        RotateL(parent);
    }
    iterator Find(const K& val)
    {
        //使用仿函数
        KeyOfT kot;
        Node* cur = _root;
        while (cur)
        {
            if (kot(cur->_value) > val)
            {
                //左子树中查找
                cur = cur->_left;
            }
            else if (kot(cur->_value) < val)
            {
                //右子树中查找
                cur = cur->_right;
            }
            else
            {
                //找到了
                return iterator(cur);
            }
        }
        //找不到返回end()
        return end();
    }

    //删除函数
    bool Erase(const K& key)
    {
        //(一)找到删除节点
        iterator it = Find(key);
        Node* cur = it.getNode();
        //未找到返回false
        if (cur == nullptr)
        {
            return false;
        }
        //记录父节点
        Node* parent = cur->_parent;
        //用于标记实际的待删除结点及其父结点
        Node* delParent = nullptr;
        Node* delCur = nullptr;
        if (cur->_left == nullptr) //待删除结点的左子树为空
        {
            if (cur == _root) //待删除结点是根结点
            {
                _root = _root->_right; //让根结点的右子树作为新的根结点
                if (_root)
                {
                    _root->_parent = nullptr;
                    _root->_col = BLACK; //根结点为黑色
                }
                delete cur; //删除原根结点
                return true;
            }
            else
            {
                delParent = parent; //标记实际删除结点的父结点
                delCur = cur; //标记实际删除的结点
            }
        }
        else if (cur->_right == nullptr) //待删除结点的右子树为空
        {
            if (cur == _root) //待删除结点是根结点
            {
                _root = _root->_left; //让根结点的左子树作为新的根结点
                if (_root)
                {
                    _root->_parent = nullptr;
                    _root->_col = BLACK; //根结点为黑色
                }
                delete cur; //删除原根结点
                return true;
            }
            else
            {
                delParent = parent; //标记实际删除结点的父结点
                delCur = cur; //标记实际删除的结点
            }
        }
        else //待删除结点的左右子树均不为空
        {
            //替换法删除
            //寻找待删除结点右子树当中key值最小的结点作为实际删除结点
            Node* minParent = cur;
            Node* minRight = cur->_right;
            while (minRight->_left)
            {
                minParent = minRight;
                minRight = minRight->_left;
            }
            // 原本直接可以赋值
            // cur->_value = minRight->_value 
            //将待删除结点的键值改为minRight的键值
            Node* newnode = new Node(minRight->_value,cur->_col);
            Node* parent = cur->_parent;
            //重新链接祖父孙三代节点关系
            cur->_left->_parent = newnode;
            cur->_right->_parent = newnode;
            if (parent)
            {
                if (parent->_left == cur)
                {
                    parent->_left = newnode;
                }
                else
                {
                    parent->_right = newnode;
                }
            }
            else
            {
                //如果是根节点
                _root = newnode;
            }
            newnode->_parent = parent;
            newnode->_left = cur->_left;
            newnode->_right = cur->_right;
            //如果minParent是cur
            if (minParent == cur)
            {
                minParent = newnode;
            }
            delete cur;
            delParent = minParent; //标记实际删除的父节点
            delCur = minRight; //标记实际删除的结点
        }
        //记录待删除结点及其父结点,便于后面删除
        Node* del = delCur;
        Node* delP = delParent;
        //(二)调整红黑树
        AdjustRBTree(delCur, delParent);
        //(三)进行实际删除
        DeleteNode(del, delP);
        return true;
    }
    void DeleteNode(Node* del, Node* delP)
    {
        if (del->_left == nullptr) //实际删除结点的左子树为空
        {
            if (del == delP->_left) //实际删除结点是其父结点的左孩子
            {
                delP->_left = del->_right;
                //指向父节点
                if (del->_right)
                    del->_right->_parent = delP;
            }
            else //实际删除结点是其父结点的右孩子
            {
                delP->_right = del->_right;
                if (del->_right)
                    del->_right->_parent = delP;
            }
        }
        else //实际删除结点的右子树为空
        {
            if (del == delP->_left) //实际删除结点是其父结点的左孩子
            {
                delP->_left = del->_left;
                if (del->_left)
                    del->_left->_parent = delP;
            }
            else //实际删除结点是其父结点的右孩子
            {
                delP->_right = del->_left;
                if (del->_left)
                    del->_left->_parent = delP;
            }
        }
        delete del; //实际删除结点
    }
    void AdjustRBTree(Node* delCur, Node* delParent)
    {
        if (delCur->_col == BLACK) //删除的是黑色结点
        {
            if (delCur->_left) //待删除结点有一个红色的左孩子(不可能是黑色)
            {
                delCur->_left->_col = BLACK; //将这个红色的左孩子变黑即可
            }
            else if (delCur->_right) //待删除结点有一个红色的右孩子(不可能是黑色)
            {
                delCur->_right->_col = BLACK; //将这个红色的右孩子变黑即可
            }
            else //待删除结点的左右均为空
            {
                while (delCur != _root) //可能一直调整到根结点
                {
                    if (delCur == delParent->_left) //待删除结点是其父结点的左孩子
                    {
                        Node* brother = delParent->_right; //兄弟结点是其父结点的右孩子
                        //情况一:brother为红色
                        if (brother->_col == RED)
                        {
                            delParent->_col = RED;
                            brother->_col = BLACK;
                            RotateL(delParent);
                            //需要继续处理
                            brother = delParent->_right; //更新brother
                        }
                        //情况二:brother为黑色,且其左右孩子都是黑色结点或为空
                        if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
                            && ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
                        {
                            brother->_col = RED;
                            if (delParent->_col == RED)
                            {
                                delParent->_col = BLACK;
                                break;
                            }
                            //需要继续处理
                            delCur = delParent;
                            delParent = delCur->_parent;
                        }
                        else
                        {
                            //情况三:brother为黑色,且其左孩子是红色结点,右孩子是黑色结点或为空
                            if ((brother->_right == nullptr) || (brother->_right->_col == BLACK))
                            {
                                brother->_left->_col = BLACK;
                                brother->_col = RED;
                                RotateR(brother);
                                //需要继续处理
                                brother = delParent->_right; //更新brother
                            }
                            //情况四:brother为黑色,且其右孩子是红色结点
                            brother->_col = delParent->_col;
                            delParent->_col = BLACK;
                            brother->_right->_col = BLACK;
                            RotateL(delParent);
                            break; //情况四执行完毕后调整一定结束
                        }
                    }
                    else //delCur == delParent->_right //待删除结点是其父结点的右孩子
                    {
                        Node* brother = delParent->_left; //兄弟结点是其父结点的左孩子
                        //情况一:brother为红色
                        if (brother->_col == RED) //brother为红色
                        {
                            delParent->_col = RED;
                            brother->_col = BLACK;
                            RotateR(delParent);
                            //需要继续处理
                            brother = delParent->_left; //更新brother
                        }
                        //情况二:brother为黑色,且其左右孩子都是黑色结点或为空
                        if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
                            && ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
                        {
                            brother->_col = RED;
                            if (delParent->_col == RED)
                            {
                                delParent->_col = BLACK;
                                break;
                            }
                            //需要继续处理
                            delCur = delParent;
                            delParent = delCur->_parent;
                        }
                        else
                        {
                            //情况三:brother为黑色,且其右孩子是红色结点,左孩子是黑色结点或为空
                            if ((brother->_left == nullptr) || (brother->_left->_col == BLACK))
                            {
                                brother->_right->_col = BLACK;
                                brother->_col = RED;
                                RotateL(brother);
                                //需要继续处理
                                brother = delParent->_left; //更新brother
                            }
                            //情况四:brother为黑色,且其左孩子是红色结点
                            brother->_col = delParent->_col;
                            delParent->_col = BLACK;
                            brother->_left->_col = BLACK;
                            RotateR(delParent);
                            break; //情况四执行完毕后调整一定结束
                        }
                    }
                }
            }
        }
    }
    ~RBTree()
    {
        Destroy(_root);
    }
private:
    void Destroy(Node*& root)
    {
        if (root == nullptr)
        {
            return;
        }
        //递归销毁左子树
        Destroy(root->_left);
        //递归销毁右子树
        Destroy(root->_right);
        //销毁根节点
        delete root;
        root = nullptr;
    }


    Node* copy(Node* root)
    {
        // 如果原始节点为空,直接返回空指针
        if (root == nullptr)
        {
            return nullptr;
        }
        // 为新节点分配内存并拷贝原始节点的值
        Node* newnode = new Node(root->_kv);
        // 递归拷贝左子树
        newnode->_left = copy(root->_left);
        // 递归拷贝右子树
        newnode->_right = copy(root->_right);
        // 将新节点的父节点指针置为空
        newnode->_parent = nullptr;
        // 拷贝原始节点的颜色信息
        newnode->_col = root->_col;
        // 如果新节点的左子节点存在,设置其父节点为新节点
        if (newnode->_left)
        {
            newnode->_left->_parent = newnode;
        }
        // 如果新节点的右子节点存在,设置其父节点为新节点
        if (newnode->_right)
        {
            newnode->_right->_parent = newnode;
        }
    }

    Node* _root = nullptr;
};

4.2 set.h

#pragma once
#include"RBTree.h"
namespace betty
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		//typename声明是一个类型而不是静态变量
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
		//成员函数
		iterator begin()
		{
			return _t.begin();
		}
		iterator end()
		{
			return _t.end();
		}
		const_iterator begin() const
		{
			return _t.begin();
		}

		const_iterator end() const
		{
			return _t.end();
		}
		pair<iterator, bool> insert(const K& key)
		{
			return _t.Insert(key);
		}
		//删除函数
		void erase(const K& key)
		{
			_t.Erase(key);
		}
		//查找函数
		iterator find(const K& key)
		{
			return _t.Find(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;
	};
}

4.3 map.c

#pragma once
#include"RBTree.h"
namespace betty
{
	template<class K, class V>
	class map
	{
		//仿函数
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		//typename声明是一个类型而不是静态变量
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator; 
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;
		//成员函数
		iterator begin()
		{
			return _t.begin();
		}
		iterator end()
		{
			return _t.end();
		}
		const_iterator begin() const
		{
			return _t.begin();
		}
		const_iterator end() const
		{
			return _t.end();
		}
		pair<iterator, bool> insert(const pair<K,V>& key)
		{
			return _t.Insert(key);
		}
		//删除函数
		void erase(const K& key)
		{
			_t.Erase(key);
		}
		//查找函数
		iterator find(const K& key)
		{
			return _t.Find(key);
		}
		//[]运算符重载
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
}
  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Betty’s Sweet

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

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

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

打赏作者

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

抵扣说明:

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

余额充值