【C++模拟实现】map、set容器的模拟实现

【C++模拟实现】map、set容器的模拟实现

目录

  • 【C++模拟实现】map、set容器的模拟实现
      • map、set模拟实现的代码(insert部分)
        • 部分一:红黑树的迭代器以及红黑树
        • 部分二:对set进行封装
        • 部分三:对map进行封装
      • 遇到的问题以及解决方案

作者:爱写代码的刚子

时间:2023.9.17

前言:本篇博客有关map、set的模拟实现,其底层采用了红黑树的结构,记录了模拟实现时的问题和解决方案。


map、set模拟实现的代码(insert部分)

部分一:红黑树的迭代器以及红黑树
enum Colour
{
    BLACK,
    RED
};


///红黑树的节点///
template<class T>
struct RBTreeNode
{
    RBTreeNode(const T& kv)
    :_left(nullptr)
    ,_parent(nullptr)
    ,_right(nullptr)
    ,_c(RED)
    ,_kv(kv)
    {}


    RBTreeNode* _left;
    RBTreeNode* _parent;
    RBTreeNode* _right;

    Colour _c; 
    T _kv;

};

//红黑树的迭代器类
template<class T,class Ref,class Ptr>
class __iterator
{
    typedef RBTreeNode<T> Node;
    typedef __iterator<T,Ref,Ptr> Self;
    
    typedef __iterator<T,T&,T*> Iterator;
public:


    __iterator(Node* it)
    :_it(it)
    {}
    //如果这个对象是const迭代器,实现的是普通迭代器转为const迭代器,
    //如果这个对象是普通迭代器,实现的是普通迭代器的拷贝构造。

    __iterator(const Iterator& t)
    :_it(t._it)
    {}

    
    Ref operator*()
    {
        return _it->_kv;
    }

    Ptr operator->()
    {
        return &_it->_kv;
    }

    Self& operator++()//前置++
    {
        if(_it->_right)
        {
            Node* subLeft=_it->_right;
            while(subLeft->_left)
            {
                subLeft=subLeft->_left;
            }

            _it=subLeft;
        }
        else{
            Node* cur = _it;
            Node* parent=_it->_parent;
            while(parent&&parent->_right==cur)
            {
                cur=cur->_parent;
                parent=cur->_parent;
            }
            _it=parent;
        }


        return *this;


    }
    Self operator++(int)//后置++
    {
        __iterator tmp(_it);
        
        if(_it->_right)
        {
            Node* subLeft=_it->_right;
            while(subLeft->_left)
            {
                subLeft=subLeft->_left;
            }

            _it=subLeft;
        }
        else{
            Node* cur = _it;
            Node* parent=_it->_parent;
            while(parent&&parent->_right==cur)
            {
                cur=cur->_parent;
                parent=cur->_parent;
            }
            _it=parent;
        }

        return tmp;
    }
///对--的重载暂时不实现(思路和++相反,将operator++中的_left换成_right,将_right换成_left即可)
  
    bool operator!=(const Self& l) const
    {
        return _it!=l._it;
    }


    bool operator==(const Self& l) const
    {
        return _it==l._it;
    }

    Node* _it;
};


//红黑树的模拟实现
template<class K,class T,class SetKeyOfT>
struct RBTree
{
    
    typedef RBTreeNode<T> Node;
    typedef __iterator<T,T&,T*> iterator;
    typedef __iterator<T,const T&,const T*> const_iterator;
 

    RBTree()
    :_root(nullptr)
    {}
//红黑树迭代器begin和end///
    iterator begin()
    {
        Node* cur=_root;
        if(!_root)
        {
            return nullptr;
        }
        while(cur->_left)
        {
            cur=cur->_left;
        }
        return iterator(cur);
    }
    iterator end()
    {
        return iterator(nullptr);
    }


    const_iterator begin() const
    {
        Node* cur=_root;
        if(!_root)
        {
            return nullptr;
        }
        while(cur->_left)
        {
            cur=cur->_left;
        }
        return const_iterator(cur);
    }

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


  	Node* Find(const K& key)
		{
			Node* cur = _root;
			SetKeyOfT k;
			while (cur)
			{
				if (k(cur->_data) < key)
				{
					cur = cur->_right;
				}
				else if (k(cur->_data) > key)
				{
					cur = cur->_left;
				}
				else
				{
          return cur;
				}
			}

			return nullptr;
		}

    pair<iterator,bool> insert(const T& kv)
    {
         if(_root==nullptr)
        {
            _root=new Node(kv);
            _root->_c=BLACK;
            return make_pair(iterator(_root),true);
        }
        
            Node* cur=_root;
            Node* parent=nullptr;
            SetKeyOfT k;

            while(cur)
            {
                if(k(cur->_kv)>k(kv))
                {
                    parent=cur;
                    cur=cur->_left;
                }
                else if(k(cur->_kv)<k(kv))
                {
                    parent=cur;
                    cur=cur->_right;
                }
                else{
                    return make_pair(iterator(cur),false);
                }
            }
            cur=new Node(kv);
            Node* newnode = cur;

/
            if(k(parent->_kv)>k(kv))
            {
                parent->_left=cur;
            }
            else{
                parent->_right=cur;
            }
            cur->_parent=parent;

      
        //需要调整的情况
        while(parent&&parent->_c==RED)
        {
            Node* grandfather=parent->_parent;

            if(grandfather->_left==parent)
            {
                Node* uncle=grandfather->_right;
                //判断uncle的几种情况


                if(uncle&&uncle->_c==RED)
                {
                    uncle->_c=parent->_c=BLACK;
                    grandfather->_c=RED;

                    cur=grandfather;
                    parent=cur->_parent;

                
                }
                else 
                {
                    if(cur==parent->_left)
                    {
                        _RotateR(grandfather);

                        grandfather->_c=RED;
                        parent->_c=BLACK;


                    }
                    else{
                        _RotateL(parent);
                        _RotateR(grandfather);

                        grandfather->_c=RED;
                        cur->_c=BLACK;


                    }
                    break;
                }
            }
            else
            {
                Node* uncle=grandfather->_left;
            
                if(uncle&&uncle->_c==RED)
                {
                    uncle->_c=parent->_c=BLACK;
                    grandfather->_c=RED;

                    cur=grandfather;
                    parent=cur->_parent;
                    
                
                }
                else 
                {
                    if(cur==parent->_right)
                    {
                        _RotateL(grandfather);
                        parent->_c=BLACK;
                        grandfather->_c=RED;
                    }
                    else{
                        _RotateR(parent);
                        _RotateL(grandfather);


                        cur->_c=BLACK;
                        grandfather->_c=RED;
                    }
                    break;

                }
                      
            }

        }
        
       
        _root->_c=BLACK;
        return make_pair(iterator(newnode),true);
    
    }
  
    void _RotateR(Node* parent)
    {
        Node*cur=parent->_left;
        Node*curRight=cur->_right;
        Node*ppnode=parent->_parent;
        
        
        cur->_right=parent;
        parent->_left=curRight;

        if(curRight)
        {
            curRight->_parent=parent;
        }
        parent->_parent=cur;
        
        //处理ppnode
        if(parent==_root)
        {
            _root=cur;
            cur->_parent=nullptr;

        }
        else
        {
            if(ppnode->_left==parent)
            {
                ppnode->_left=cur;
            }
            else{
                ppnode->_right=cur;
            }
            cur->_parent=ppnode;
        }
     

    }

    void _RotateL(Node* parent)
    {
        Node* cur=parent->_right;
        Node* curLeft=cur->_left;
        Node* ppnode=parent->_parent;

        cur->_left=parent;
        parent->_right=curLeft;

        if(curLeft)
        {
            curLeft->_parent=cur;
        }
        parent->_parent=cur;

        if(parent==_root)
        {
            _root=cur;
            cur->_parent=nullptr;
        }
        else
        {
            if(ppnode->_left==parent)
            {
                ppnode->_left=cur;
            }
            else{
                ppnode->_right=cur;
            }
            cur->_parent=ppnode;
        }  
    }
    Node* _root;
};
部分二:对set进行封装
template<class K>
class set
{
    struct SetKeyOfT
    {
        const K& operator()(const K& key)//仿函数
        {
            return key; 
        }
    };
public:
    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)
    {
        pair<typename RBTree<K,K,SetKeyOfT>::iterator,bool> ret= _t.insert(key);//这边我们需要注意,右边是普通迭代器,左边是const迭代器,我们需要实现普通迭代器构造const迭代器
        return pair<iterator,bool>(ret.first,ret.second);
    }

private:
    RBTree<K,K,SetKeyOfT> _t;
    
};
部分三:对map进行封装
template<class K,class V>
class map
{
    struct MapKeyOfT
    {
        const K& operator()(const pair<K,V>& kv)
        {
            return kv.first;
        }

    };
public:
    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>& kv)
    {
        return _t.insert(kv);
    }


    V& operator[](const K&key)
    {
        pair<iterator,bool> ret = insert(make_pair(key,V()));
        return ret.first->second;
    }

private:
    RBTree<K,pair<const K,V>,MapKeyOfT> _t;
};

遇到的问题以及解决方案

  • 【问题】:由于map和set共用一颗树的结构,但是传入的数据类型并不相同,set直接插入key,而map要插入pair。在树里面全部采用统一的模版参数T。在insert的比较大小环节会出现错误,pair不能直接进行大小的比较(虽然库里面pair有进行大小比较的重载函数但是效果并不符合预期)

    【解决】:在set和map的结构体里写一个仿函数,在树里面调用名称相同但是功能不同的仿函数,达到对数据的统一比较的效果。

    map:

    【C++模拟实现】map、set容器的模拟实现_第1张图片
    【C++模拟实现】map、set容器的模拟实现_第2张图片

    set:

【C++模拟实现】map、set容器的模拟实现_第3张图片

【C++模拟实现】map、set容器的模拟实现_第4张图片

红黑树:

【C++模拟实现】map、set容器的模拟实现_第5张图片

【C++模拟实现】map、set容器的模拟实现_第6张图片

红黑树中的SetKeyOfT可以是其他名字,不要和set中的SetKeyOfT搞混了。

  • 【问题】:普通迭代器如何构造const迭代器?

    由于set不能对数据进行修改,所以set的迭代器的下面使用红黑树的const迭代器实现的:

    在这里插入图片描述

    观察set对insert函数的封装:
    【C++模拟实现】map、set容器的模拟实现_第7张图片

​ 由于set调用红黑树的insert函数而红黑树中insert函数默认返回iterator迭代器,而```pair insert(const K& key)``使用的是set中对红黑树中const迭代器封装后的迭代器,insert的返回值和该函数的返回值不相同,需要进行转换,由于红黑树中的迭代器没有实现转换就会出现以下报错:

【C++模拟实现】map、set容器的模拟实现_第8张图片

【解决】:在红黑树的迭代器中实现普通迭代器对const迭代器的转换:

【C++模拟实现】map、set容器的模拟实现_第9张图片

  • 【问题】:如何实现map的pair中的key不能被修改?

    【解决】:【C++模拟实现】map、set容器的模拟实现_第10张图片

    注意!以下传入红黑树的模版参数中也需要加上const:在这里插入图片描述

  • 留意红黑树迭代器中的iterator++中的算法:

【C++模拟实现】map、set容器的模拟实现_第11张图片

  • 在实现迭代器时,这两个运算符是一定要重载的:
    【C++模拟实现】map、set容器的模拟实现_第12张图片

  • Map中对[]的重载方法:

    【C++模拟实现】map、set容器的模拟实现_第13张图片

你可能感兴趣的:(C++进阶,c++,rpc,java,数据结构,map,set)