【C++】模拟实现map和set

目录

红黑树的介绍

封装版本的红黑树

新增加的部分(迭代器)

map的模拟实现

set的模拟实现


红黑树的介绍

  • 大家可以去看我之前的博客模拟实现红黑树,里面详细的介绍了红黑树的主题逻辑,本文着重介绍迭代器和封装

封装版本的红黑树

  • 新版本红黑树的完整代码

#pragma once

namespace HQJ
{
 enum Color
 {
  RED,
  BLACK
 };

 //template<class K ,class V>这里不用data是为了封装做准备
 template<class T>//
 struct RBTreeNode
 {
  RBTreeNode<T>* _left;
  RBTreeNode<T>* _right;
  RBTreeNode<T>* _parent;
  T _data;
  Color _color;

  RBTreeNode(const T& data)
   :_left(nullptr)
   , _right(nullptr)
   , _parent(nullptr)
   , _data(data)
   , _color(RED)
  {}
 };

 template<class T>
 struct _iterator
 {
  typedef RBTreeNode<T> Node;
  typedef _iterator<T> self;
  Node* _node;

  _iterator(Node* node)
   :_node(node)
  {}

  self& operator++()
  {
   if (_node->_right != nullptr)
   {
    Node* cur = _node->_right;

    while (cur && cur->_left)
    {
     cur = cur->_left;
    }
    _node = cur;
   }
   else
   {
    Node* cur = _node;
    Node* parent = _node->_parent;

    while (parent && cur == parent->_right)
    {
     cur = parent;
     parent = cur->_parent;
    }
    _node = parent;
   }
   return *this;
  }
  
  bool operator!=(const self& node)
  {
   return _node != node._node;
  }

  bool operator==(const self& node)
  {
   return (*this != node);
  }
  T* operator->()
  {
   return &(_node->_data);
  }

  T& operator*()
  {
   return _node->_data;
  }
 };

 template<class K, class V, class keyOfT>
 class RBTree
 {
 public:
  typedef RBTreeNode<V> Node;
  typedef _iterator<V> iterator;
  iterator begin()
  {
   Node* cur = _root;
   while (cur && cur->_left)
   {
    cur = cur->_left;
   }

   return iterator(cur);
  }

  iterator end()
  {
   return iterator(nullptr);
  }
  bool Insert(const V& data)
  {
   if (_root == nullptr)
   {
    _root = new Node(data);
    _root->_color = BLACK;
    return true;
   }

   Node* parent = nullptr;
   Node* cur = _root;

   while (cur)
   {
    if (_kot(cur->_data) < _kot(data))
    {
     parent = cur;
     cur = cur->_right;
    }
    else if (_kot(cur->_data) > _kot(data))
    {
     parent = cur;
     cur = cur->_left;
    }
    else
    {
     return false;
    }
   }

   cur = new Node(data);
   cur->_color = RED;
   if (_kot(parent->_data) < _kot(data))
   {
    parent->_right = cur;
    cur->_parent = parent;
   }
   else
   {
    parent->_left = cur;
    cur->_parent = parent;
   }

   while (parent && parent->_color == RED)
   {
    Node* grandfather = parent->_parent;
    if (parent == grandfather->_left)
    {
     Node* uncle = grandfather->_right;
     if (uncle && uncle->_color == RED)
     {
      parent->_color = uncle->_color = BLACK;
      grandfather->_color = RED;

      cur = grandfather;
      parent = cur->_parent;
     }
     else
     {
      if (cur == parent->_left)
      {
       RotateR(grandfather);
       parent->_color = BLACK;
       grandfather->_color = RED;
      }
      else
      {
       RotateL(parent);
       RotateR(grandfather);
       cur->_color = BLACK;
       grandfather->_color = RED;
      }

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

      cur = grandfather;
     }
     else
     {
      if (cur == parent->_right)
      {
       RotateL(grandfather);
       parent->_color = BLACK;
       grandfather->_color = RED;
      }
      else
      {
       RotateR(parent);
       RotateL(grandfather);
       cur->_color = BLACK;
       grandfather->_color = RED;
      }

      break;
     }
    }
   }

   _root->_color = BLACK;

   return true;
  }

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

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

   Node* parentParent = parent->_parent;

   parent->_parent = subR;
   if (subRL)
    subRL->_parent = parent;

   if (_root == parent)
   {
    _root = subR;
    subR->_parent = nullptr;
   }
   else
   {
    if (parentParent->_left == parent)
    {
     parentParent->_left = subR;
    }
    else
    {
     parentParent->_right = subR;
    }

    subR->_parent = parentParent;
   }
  }

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

   parent->_left = subLR;
   if (subLR)
    subLR->_parent = parent;

   Node* parentParent = parent->_parent;

   subL->_right = parent;
   parent->_parent = subL;

   if (_root == parent)
   {
    _root = subL;
    subL->_parent = nullptr;
   }
   else
   {
    if (parentParent->_left == parent)
    {
     parentParent->_left = subL;
    }
    else
    {
     parentParent->_right = subL;
    }

    subL->_parent = parentParent;
   }
  }

  void InOrder()
  {
   _InOrder(_root);
   cout << endl;
  }

  void _InOrder(Node* root)
  {
   if (root == nullptr)
    return;

   _InOrder(root->_left);
   cout << root->_data.first << " ";
   _InOrder(root->_right);
  }

 private:
  // 根节点->当前节点这条路径的黑色节点的数量
  bool Check(Node* root, int blacknum, const int refVal)
  {
   if (root == nullptr)
   {
    //cout << balcknum << endl;
    if (blacknum != refVal)
    {
     cout << "存在黑色节点数量不相等的路径" << endl;
     return false;
    }

    return true;
   }

   if (root->_color == RED && root->_parent->_color == RED)
   {
    cout << "有连续的红色节点" << endl;

    return false;
   }

   if (root->_color == BLACK)
   {
    ++blacknum;
   }

   return Check(root->_left, blacknum, refVal)
    && Check(root->_right, blacknum, refVal);
  }
 public:
  bool IsBalance()
  {
   if (_root == nullptr)
    return true;

   if (_root->_color == RED)
    return false;

   //参考值
   int refVal = 0;
   Node* cur = _root;
   while (cur)
   {
    if (cur->_color == BLACK)
    {
     ++refVal;
    }

    cur = cur->_left;
   }

   int blacknum = 0;
   return Check(_root, blacknum, refVal);
  }

 private:
  Node* _root = nullptr;
  keyOfT _kot;
 };
}

新增加的部分(迭代器)

  • 成员变量

Node* _node;:指向当前迭代器所代表的红黑树节点的指针。

  • 构造函数

_iterator(Node* node) : _node(node) {}:接收一个指向红黑树节点的指针,并将其赋值给_node。

  • 前置递增运算符 operator++()

这个函数实现了迭代器的前置递增操作,即将迭代器移动到下一个节点。如果当前节点有右子树,则找到右子树中的最左侧节点作为下一个节点。如果当前节点没有右子树,则沿着父节点的链向上遍历,直到找到一个节点,该节点是其父节点的左子节点,或者遍历到根节点(即没有更多的父节点)。更新_node以指向新的节点。

  • 不等运算符 operator!=()

比较当前迭代器和另一个迭代器是否指向不同的节点。 如果两个迭代器的_node指针不同,则返回true,否则返回false。

  • 相等运算符 operator==()

比较当前迭代器和另一个迭代器是否指向相同的节点。实际上,这里的实现是通过调用operator!=()并返回其反值,可能不是最高效的实现方式,但逻辑上没有问题。

  • 解引用运算符 operator->()

允许通过迭代器直接访问节点的数据成员,类似于指针的解引用。 返回一个指向节点数据成员的指针。

  • 解引用运算符 operator*()

返回当前节点所存储的数据的引用。通过这个运算符,可以直接修改红黑树节点的数据。

template<class T>
 struct _iterator
 {
  typedef RBTreeNode<T> Node;
  typedef _iterator<T> self;
  Node* _node;

  _iterator(Node* node)
   :_node(node)
  {}

  self& operator++()
  {
   if (_node->_right != nullptr)
   {
    Node* cur = _node->_right;

    while (cur && cur->_left)
    {
     cur = cur->_left;
    }
    _node = cur;
   }
   else
   {
    Node* cur = _node;
    Node* parent = _node->_parent;

    while (parent && cur == parent->_right)
    {
     cur = parent;
     parent = cur->_parent;
    }
    _node = parent;
   }
   return *this;
  }
  
 
  bool operator!=(const self& node)
  {
   return _node != node._node;
  }

  bool operator==(const self& node)
  {
   return (*this != node);
  }
  T* operator->()
  {
   return &(_node->_data);
  }

  T& operator*()
  {
   return _node->_data;
  }
 };

map的模拟实现

  • 模板参数

myMap有两个模板参数:K和V,分别代表键(Key)的类型和值(Value)的类型。

  • 成员函数

  1. Insert(const pair<K, V>& data) 这个函数接受一个pair<K, V>类型的参数,并尝试将其插入到红黑树中。它直接调用红黑树的Insert函数来完成插入操作。

  2. 内部结构体 MapkeyOfT 这个结构体定义了一个函数对象(也称为仿函数),它接受一个pair<K, V>类型的参数,并返回其键(即pair的first成员)。这个函数对象被用作红黑树的键提取函数,以便红黑树能够正确地根据键来排序和查找节点。

  3. typedef别名 iterator 这里使用typedef为红黑树的迭代器类型定义了一个别名iterator。这个别名使得myMap的用户可以更方便地引用和使用迭代器。

  4. begin() 和 end() 这两个函数分别返回指向红黑树中第一个节点和尾后节点的迭代器。它们允许用户遍历myMap中的所有元素。

  • 私有成员

_tree是一个红黑树对象,它使用K作为键类型,pair<K, V>作为值类型,并使用MapkeyOfT作为键提取函数。

  • 模拟实现的全部代码

#pragma once
#include"RBTree.h"
namespace HQJ
{
 template<class K, class V>
 class myMap
 {
 public:
  
  bool Insert(const pair<K, V>& data)
  {
   return _tree.Insert(data);
  }

  struct MapkeyOfT
  {
   const K& operator()(const pair<K, V>& data)
   {
    return data.first;
   }
  };

  typedef typename RBTree<K, pair<K, V>, MapkeyOfT>::iterator iterator;

  iterator begin()
  {
   return _tree.begin();
  }

  iterator end()
  {
   return _tree.end();
  }
 private:
  RBTree<K, pair<K, V>, MapkeyOfT> _tree;
 };
}

set的模拟实现

  • 模板参数

mySet有一个模板参数K,代表集合中元素的类型。

  • 成员函数

  1. Insert(const K& data) 这个函数接受一个类型为K的参数,并尝试将其插入到红黑树中。它直接调用红黑树的Insert函数来完成插入操作。

  2. 内部结构体 SetkeyOfT 这个结构体定义了一个函数对象(也称为仿函数),它接受一个类型为K的参数,并返回该参数本身。这个函数对象被用作红黑树的键提取函数,以便红黑树能够正确地根据键来排序和查找节点。对于集合来说,键和值实际上是相同的,因此这个函数对象只是简单地返回了传入的参数。

  3. typedef别名 iterator 这里使用typedef为红黑树的迭代器类型定义了一个别名iterator。这个别名使得mySet的用户可以更方便地引用和使用迭代器。

  4. begin() 和 end() 这两个函数分别返回指向红黑树中第一个节点和尾后节点的迭代器。它们允许用户遍历mySet中的所有元素。

  • 私有成员

_tree是一个红黑树对象,它使用K作为键类型和值类型,并使用SetkeyOfT作为键提取函数。由于集合中键和值是相同的,因此这里使用了相同的类型K作为键和值。

  • 模拟实现的全部代码

#pragma once
#include"RBTree.h"

namespace HQJ
{
 template<class K>
 class mySet
 {
 public:
  
  bool Insert(const K& data)
  {
   return _tree.Insert(data);
  }

  struct SetkeyOfT
  {
   const K& operator()(const K& data)
   {
    return data;
   }
  };

  typedef typename RBTree<K, K, SetkeyOfT>::iterator iterator;

  iterator begin()
  {
   return _tree.begin();
  }

  iterator end()
  {
   return _tree.end();
  }
 private:
  RBTree<K, K, SetkeyOfT> _tree;
 };
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值