Cpp || 模拟实现set

set底层的红黑树实现
#pragma  once
#include<iostream>
#include<functional>
using namespace std;
 
enum Color{
  Red,
  Black
};

template <class T>

struct RBTNode{
  RBTNode(const T& kv=T(),Color color=Red)
    :_kv(kv)
     ,_color(color)
     ,_left(nullptr)
     ,_right(nullptr)
     ,_parent(nullptr)
  {

  }
  T  _kv;
  Color _color;
  RBTNode<T>* _left;
  RBTNode<T>* _right;
  RBTNode<T>* _parent;
};

template <class T>
struct RBTreeIterator{
  typedef RBTNode<T> Node;
  typedef Node* pNode;
  typedef RBTreeIterator<T> Self;

  RBTreeIterator(pNode  PNode)
    :_pNode(PNode)
  {

  }

  RBTreeIterator()
    :_pNode(nullptr)
  {

  }

  RBTreeIterator(const Self&  s)
    :_pNode(s._pNode)
  {

  }
  //具有指针的操作
  T& operator*(){
    return _pNode->_kv;
  }

  T*  operator->(){
    //return &(operator*());
    //一般不直接取,通过解引用的方式来取地址
    return &_pNode->_kv;
  }

  //迭代器的移动
  //前置++
  Self& operator++(){
    Increament();
    return *this;
  }

  Self operator++(int){
    Self temp(*this);
    Increament();
    return temp;
  }

  //前置--
  Self& operator--(){
    DeIncreament();
    return *this;
  }

  Self operator--(int){
    Self temp(*this);
    DeIncreament();
    return temp;
  }

  bool operator==(const Self& s)const{
    return _pNode==s._pNode;
  }

  bool operator!=(const Self& s)const{
    return _pNode!=s._pNode;
  }

  private:

  void Increament(){
    if(_pNode->_right){
      _pNode=_pNode->_right;
      while(_pNode->_left){
        _pNode=_pNode->_left;
      }
    }else{
      //比_pNode大的元素可能在其双亲中
      Node* parent=_pNode->_parent;
      while(_pNode==parent->_right){
        _pNode=parent;
        parent=_pNode->_parent;
      }

      //根结点没有右子树,并且迭代器正好在根结点的位置
      if(_pNode->_right!=parent)
        _pNode=parent;
    }
  }

  void DeIncreament(){
    //end--能够走到最大节点的位置

    if (_pNode->_parent->_parent == _pNode&& Red==_pNode->_color){
    
      //当_pNode符合_pNode->_parent->_parent==_pNoded 
      //的时候说明_pNode是根结点或者_head,
      //_pNode->_color==Red则派出了_pNode是根结点的情况
      //则_pNode指向的是_head,其--指向了该树种最大的结点
      _pNode = _pNode->_right;
    }
    else if (_pNode->_left){
      //如果左子树存在,在左子树中找最大的节点
      _pNode = _pNode->_left;
      while (_pNode->_right){
        _pNode = _pNode->_right;
      }
    }
    else{
      //如果这个左子树不存在,就从该节点开始向上找
      Node* pParent = _pNode->_parent;
      while (_pNode == pParent->_left){
        _pNode = pParent;
        pParent = _pNode->_parent;
      }
      _pNode = pParent;
    }
  
  }
    private:
  Node* _pNode;
};

template <class K,class V,class KeyOfValue>

//因为关联式容器中的存储的是<Key,Value>的键值对,因此k为Key的类型
//ValueType:如果是map,则为pair<k,V>;如果是set,则为K
//KeyOfValue;通过value来获取key的一个仿函数
class RBTree{
  public:
    typedef RBTNode<V> Node;
    typedef Node*  pNode;
    typedef RBTreeIterator<V> Iterator;
   

    Iterator Begin(){
      return Iterator(_head->_left);
    }

    Iterator End(){
      return Iterator(_head);
    }

    Iterator Find(const V&data)const{
      pNode cur=_head->_parent;

      while(cur){
        if(KeyOfValue(data)==KeyOfValue(cur->_kv)){
          return Iterator(cur);
        
        }else if(KeyOfValue(data)<KeyOfValue(cur->_kv)) {
          cur=cur->_left;
        }else{
          cur=cur->_right;
        }
       return End();//没找到
    }
  }

    bool Empty()const{
      return _head->_parent==nullptr;
    }

    size_t Size()const{
      return _size;
    }
    /// 
    //Modify
    //在红黑树中插入data的键值对
    //若data中的key已经在红黑树中,则插入失败,返回<该结点的Iteator,false>
    //若data中的key不存在,则插入成功,返回<新的结点的迭代器,true>
    

  public:
    RBTree()
      :_size(0)
    {
      _head=new Node;
      _head->_left=_head;
      _head->_right=_head;
    }


    pair<Iterator,bool>  Insert(const V& kv){

      pNode pRoot=GetRoot();
      pNode pNewNode=nullptr;
    
      if(pRoot==nullptr){

        //第一次插入的时候插入的是根结点,且颜色为黑色
        /*pNode _root=new Node(kv);
        _root->_color=Black;
        _root->_parent=_head;
        _head->_left=_root;
        _head->_right=_root;
        _head->_parent=_root;
        return true;
        */
        pNewNode=pRoot=new Node(kv,Black);
        pRoot->_parent=_head;
        _head->_parent=pRoot;
        _head->_left=pRoot;
        _head->_right=pRoot;
        ++_size;
        return make_pair(Iterator(pNewNode),true);
      }
      else 
      {  //处理存在根结点的情况


        pNode cur=pRoot;

        pNode parent=nullptr;
        while(cur){
          parent=cur;
          if(KeyOfValue(cur->_kv) > KeyOfValue(kv)){
          
            cur=cur->_left;
          }else if(KeyOfValue(kv) > KeyOfValue(cur->_kv)){

            cur=cur->_right;
          }else{
            return make_pair(Iterator(cur),false);
          }
        }

        //进行插入
       pNewNode=cur=new Node(kv);


        if(KeyOfValue(cur->_kv) < KeyOfValue(parent->_kv)){
          parent->_left=cur;
        }else{
          parent->_right=cur;
        }

        cur->_parent=parent;

        //进行调整变色
        while(cur!=pRoot && parent->_color==Red){
   
          pNode gparent=parent->_parent;
          if(gparent->_left==parent){
            pNode uncle=gparent->_right;
            //u存在且为红
            if(uncle && uncle->_color==Red){
              //情况一
              parent->_color=Black;
              uncle->_color=Black;
              gparent->_color=Red;
              cur=gparent;
              parent=cur->_parent;
            }else{
              //u不存在 / 存在且为黑
              //1.以g为轴右旋
              //2.调整颜色,p为黑色,g为红色

              //检查是否为双旋场景:左右双旋
              if(parent->_right==cur){
                RotateL(parent);
                swap(parent,cur);
              }
              RotateR(gparent);
              parent->_color=Black;
              gparent->_color=Red;
              break;
            }
          }else{
            pNode uncle=gparent->_left;
            if(uncle && uncle->_color==Red){
              parent->_color=uncle->_color=Black;
              gparent->_color=Red;
              cur=gparent;
              parent=cur->_parent;

            }else{
              //u存在且为黑/u不存在
              if(parent->_left==cur){
                RotateR(parent);
                swap(cur,parent);
              }

              RotateL(gparent);
              gparent->_color=Red;
              parent->_color=Black;
              break; 
            }
          }

        }
      } 

      ++_size;
      //红黑树根始终是黑色的
      pRoot->_color=Black;
      //为了实现后续的迭代器,将head的左右指针指向最大,最小的值
      _head->_left=leftMost();
      _head->_right=rightMost();

      return make_pair(Iterator(pNewNode),true); 

    }

    pNode leftMost(){

      pNode pRoot=GetRoot();

      if(pRoot==nullptr){
        return _head;
      }
      pNode cur=pRoot;
      while(cur && cur->_left){
        cur=cur->_left;
      }
      return cur;
    }

    pNode rightMost(){

      pNode pRoot=GetRoot();
      if(pRoot==nullptr){
        return _head;
      }
      pNode cur=pRoot;
      while(cur && cur->_right){
        cur=cur->_right;
      }
      return cur;
    }

    void RotateL(pNode parent){
      pNode subR=parent->_right;
      pNode subRL=subR->_left;

      subR->_left=parent;
      parent->_right=subRL;

      if(subRL){
        subRL->_parent=parent;
      }

      if(parent!=_head->_parent){
        pNode gparent=parent->_parent;

        //判断parent之前是parent->_parent 的那一边的结点
        //把subR链接到对应的边
        if(gparent->_left==parent)
          gparent->_left=subR;
        else 
          gparent->_right=subR;
        //更新subR的parent
        subR->_parent=gparent;
      }
      else {
        //如果parent是根,subR变成新的根
        subR->_parent=_head;
        _head->_parent=subR;
      }

      //链接subR与parent
      parent->_parent=subR;      
    }

   void RotateR(pNode parent){
     pNode subL=parent->_left;
     pNode subLR=subL->_right;

     //1.单向链接subL,subLR,parent
     subL->_right=parent;
     parent->_left=subLR; 
     //2.向上链接subLR,parent 
     if(subLR){
       subLR->_parent=parent;
     }
     //3.双向链接subL与parent<_parent 
     if(parent!=_head->_parent){
       pNode gParent=parent->_parent;

       if(gParent->_left==parent){
         gParent->_left=subL;
       }else{
         gParent->_right=subL; 
       }

       //把subL的父亲结点改成其祖宗结点
       subL->_parent=gParent;
     }else{
       subL->_parent=_head;
       _head->_parent=subL; 
     }
     //4.向上链接parent,subL 
     parent->_parent=subL;
   }


    void Inorder(){
      _Inorder(_head->_parent);
      cout<<endl;
    }

    bool IsValidRBTree()
    {
      pNode pRoot = GetRoot();

      // 空树也是红黑树
      if (nullptr == pRoot)
        return true;

        // 检测根节点是否满足情况
        if (Black != pRoot->_color)
        {
          cout << "违反红黑树性质一:根节点必须为黑色!" << endl;
          return false;
        }
      // 获取任意一条路径中黑色节点的个数
      size_t blackCount = 0;
      pNode pCur = pRoot;
      while (pCur)
      {
        if (Black == pCur->_color)
          blackCount++;
        pCur = pCur->_left;
      }
      // 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
      size_t k = 0;
      return _IsValidRBTree(pRoot, k, blackCount);
    }

  private:
    void _Inorder(pNode parent){
      if(parent){
        _Inorder(parent->_left);
        cout<<"Key:"<<parent->_kv.first<<"Value:"<<parent->_kv.second<<endl;
        _Inorder(parent->_right);
      }
    }

    pNode& GetRoot(){
      return _head->_parent;
    }

    
    bool _IsValidRBTree(pNode pRoot, size_t k, const size_t blackCount) {
      //走到null之后,判断k和black是否相等
      if (nullptr == pRoot)
      {
        if (k != blackCount)
        {
          cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
          return false;
        }
        return true;
      }

      // 统计黑色节点的个数
      if (Black == pRoot->_color)
        k++;
      // 检测当前节点与其双亲是否都为红色
      pNode pParent = pRoot->_parent;
      if (pParent && Red == pParent->_color && Red == pRoot->_color)
      {
        cout << "违反性质三:没有连在一起的红色节点" << endl;
        return false;
      }
      return _IsValidRBTree(pRoot->_left, k, blackCount) &&
        _IsValidRBTree(pRoot->_right, k, blackCount);
    }

  private:
    pNode _head;
    size_t _size;  //用于记录有效结点个数
};
对底层进行封装的Set.hpp
#pragma once
#include"RBTree.hpp"

namespace  bite{ 
  template<class K>

    class Set{

      typedef K ValueType;
      public:
      typedef typename RBTree<K,K,ValueType>::Iterator Iterator;

      pair<Iterator,bool> Insert(const ValueType& key){
        return _t.Insert(key);
      }

      Iterator begin(){
        return _t.Begin();
      }

      Iterator end(){
        return _t.End();
      }

      bool empty(){
        return _t.Empty();
      }
 
      K& operator[](const K& key){
        K ret=_t.Insert(key);
        return ret;
      }
      private:
      RBTree<K,K,ValueType> _t;
    };
}
  • 特别注意
  • 对于set而言,在进行键值对插入的时候,其键和值都是相同的
对模拟实现的Set进行测试
#include"Set.hpp"
#include<iostream>

using namespace std;

void TestSet(){
  bite::Set<int> set;
  set.Insert(0);
  set.Insert(9);

  //先去执行operator[]操作(既插入的结点中first为[]中的值,second值为默认的类型值) 
  //执行完插入操作之后,执行return ret.first->second 
  //(既return ret.first.operator->()后去执行->second)
  //其中operator->()返回的值结点中kv的地址,
  //返回后将set[3]中second中默认的值改为100


  for(auto& e:set){
    cout<<e<<endl;
  }

  cout<<"该容器中是否为空:"<<set.empty()<<endl;
}


int main(){
  TestSet();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++中,当出现错误提示"unordered_set does not name a"时,通常是因为没有包含正确的头文件。为了解决这个问题,你需要包含`<unordered_set>`头文件。这个头文件包含了`unordered_set`的定义和相关的函数和操作符。 此外,有时在某些编译环境中,可能需要添加一些额外的设置才能使用C++11的语法和特性,如`auto`关键字。在VS Code中,你可以通过编辑`settings.json`文件来添加这些设置。 对于Mac用户,你可以使用快捷键Shift+Command+P打开命令面板,并输入"settings.json"来打开`settings.json`文件。然后,你可以添加以下代码片段到`settings.json`中: ```json "code-runner.executorMap": { "cpp": "g++ $fileName -std=c++17 -o $fileNameWithoutExt.exe && ./$fileNameWithoutExt.exe" } ``` 这段代码将设置Code Runner插件在运行C++代码时使用g++编译器,并将C++标准设置为C++17。这样就可以使用`unordered_set`和其他C++11的语法了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [error: ‘unordered_set’ in namespace ‘std’ does not name a template type](https://blog.csdn.net/qq_44328440/article/details/130713051)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [unordered_map和unordered_set的模拟实现](https://download.csdn.net/download/weixin_38629362/14886751)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Mac Vscode使用C++11,用unordered_set报错或者报错报警告](https://blog.csdn.net/qq_21237549/article/details/124778301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值