红黑树封装实现STL-map、set

简介: 红黑树封装实现STL-map、set

利用红黑树作为模板封装的思路

将红黑树作为一个基础的类模板,通过给这个类模板传递不同的参数,从而控制它所实现的容器。

最主要的点是用自己的map和set通过传递不同的模板参数控制红黑树第二个模板参数 T 来确定传入的到底是 Key 还是 pair<Key, Value> 类型的模板参数【泛型编程的思想】,如下图

红黑树的第二个参数T,通过传入参数的不同,控制红黑树中到底存储什么类型的变量。

给红黑树传的第三个模板参数 KeyOfT 是一个类,这个类中重载了 operator(),它实例化出的对象可以当做函数来使用,并且这个函数可以实现多种不同数据类型的大小比较,通过传进来类的不同,来使用不同的比较方式。

如图,KeyOfT示例化出的对象kot来进行树中的大小比较,当传 SetKeyOfT 时,就使用 key 作为比较依据;当传 MapKeyOfT 时,就使用 kv.first 作为大小比较依据。

迭代器的封装

首先,需要写一个迭代器的类模板,里面有迭代器变量主要需要使用的一些功能,如++,->,*,!=,==等等这些,通过传递不同的参数,来构造不同类型的迭代器。

迭代器的内部成员变量就是一个红黑树结点类型的指针,通过重载++,--,->等运算符作为成员函数。而模板参数传 Ref 和 Ptr 的原因是:当构造的是 const 类型或 非const 类型的迭代器时,编译器可以自己推导出返回值的类型。因为普通迭代器 iterator 和const类型的迭代器 const_iterator 不是同一个类型!

在红黑树中根据模板参数的不同重定义两个不同的迭代器:普通迭代器和 const 迭代器。当使用普通迭代器时,相当于给迭代器模板传<T, T&, T*>;当使用 const迭代器 时,相当于给迭代器模板传<T, const T&, const T*>

map 和 set 内部对于迭代器的处理

stl中 set 里的 key 不允许改变,因此无论是 iterator 还是 const_iterator,都需要使用红黑树中定义的 const_iterator 迭代器来初始化。

而map中,key不允许改变,T却可以改变,直接在模板参数中加 const 修饰K,普通迭代器用iterator,const 迭代器用 const_iterator修饰。

将insert 的返回值设置为 pair 类型,第一个 first 参数为 Node* 类型,因为无论是普通迭代器还是 const类型的迭代器,都是用 Node* 类型的变量来初始化的,只要是相近类型,pair的拷贝构造函数都能进行构造推导,推导为正确的类型!

代码实现

RBTree.h

#pragma once
#pragma once
#include<iostream>
#include<string>
#include<stdbool.h>
using namespace std;
typedef enum Color
{
  RED,  // 红色
  BLACK // 黑色
}Color;
template<class T>
struct RBTreeNode
{
  RBTreeNode(const T& data)
    :_right(nullptr)
    , _left(nullptr)
    , _parent(nullptr)
    , _col(RED)
    , _data(data)
  {}
  RBTreeNode<T>* _right;
  RBTreeNode<T>* _left;
  RBTreeNode<T>* _parent;
  // 颜色:枚举类型
  Color _col;
  T _data;
};
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
  typedef RBTreeNode<T> Node;
  typedef __TreeIterator<T, Ref, Ptr> self;
  Node* _node;
  __TreeIterator(Node* node)
    :_node(node)
  {}
  self& operator--()
  {
    if (_node->_left)
    {
      Node* cur = _node->_left;
      while (cur->_right)
      {
        cur = cur->_right;
      }
      _node = cur;
    }
    else
    {
      // 等于空,说明当前结点已经访问结束了。
      // 向上回溯,直到孩子是父亲左节点的孩子
      Node* cur = _node;
      Node* parent = _node->_parent;
      while (parent && cur == parent->_left)
      {
        cur = parent;
        parent = parent->_parent;
      }
      _node = parent;
    }
    return *this;
  }
  self& operator++()
  {
    if (_node->_right)
    {
      Node* cur = _node->_right;
      while (cur->_left)
      {
        cur = cur->_left;
      }
      _node = cur;
    }
    else
    {
      // 等于空,说明当前结点已经访问结束了。
      // 向上回溯,直到孩子是父亲左节点的孩子
      Node* cur = _node;
      Node* parent = _node->_parent;
      while (parent && cur == parent->_right)
      {
        cur = parent;
        parent = parent->_parent;
      }
      _node = parent;
    }
    return *this;
  }
  bool operator==(const self& it)
  {
    return _node == it._node;
  }
  bool operator!=(const self& it)
  {
    return _node != it._node;
  }
  Ptr operator->()
  {
    return &_node->_data;
  }
  Ref operator*()
  {
    return _node->_data;
  }
};
template<class K, class T, class KeyOfT>
class RBTree
{
  typedef RBTreeNode<T> Node;
public:
  typedef __TreeIterator<T, T&, T*> iterator;
  typedef __TreeIterator<T, const T&, const T*> const_iterator;
  KeyOfT kot;
  iterator begin()
  {
    Node* cur = _root;
    while (cur->_left)
    {
      cur = cur->_left; /*_t = cur; // 这个 _t 是根节点,不能随便变*/
    }
    return iterator(cur); //return *this;迭代器这里不能返回引用
  }
  iterator end()
  {
    return iterator(nullptr);
  }
  const_iterator begin() const
  {
    Node* cur = _root;
    while (cur->_left)
    {
      cur = cur->_left;
    }
    return const_iterator(cur);
  }
  const_iterator end() const
  {
    return const_iterator(nullptr);
  }
  pair<Node*, bool> Insert(const T& data)
  {
    if (_root == nullptr)
    {
      _root = new Node(data);
      _root->_col = BLACK;
      return make_pair(_root, 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 make_pair(cur, false);
      }
    }
    cur = new Node(data); // 初始化的时候就是红色结点
    cur->_parent = parent;
    // 调整父子之间的关系
    if (kot(parent->_data) < kot(data))
      parent->_right = cur;
    else if (kot(parent->_data) > kot(data))
      parent->_left = cur;
    Node* grandparent = parent->_parent;
    while (parent && parent->_col == RED)
    {
      grandparent = parent->_parent;
      Node* uncle = nullptr;
      // 调整父亲和叔叔与爷爷的关系
      if (kot(parent->_data) > kot(grandparent->_data))
      {
        grandparent->_right = parent;
        uncle = grandparent->_left;
      }
      else if (kot(parent->_data) < kot(grandparent->_data))
      {
        grandparent->_left = parent;
        uncle = grandparent->_right;
      }
      // 新插入结点的父亲是红色结点,需要调整
      // 调整父亲和叔叔的左右
      if (uncle && uncle->_col == RED) // 叔叔存在并且为红色
      {
        grandparent->_col = RED;
        uncle->_col = parent->_col = BLACK;
        cur = grandparent;
        parent = cur->_parent;
      }
      else if (uncle == nullptr || uncle->_col == BLACK) // 叔叔不存在或者存在且为黑色,需要调整加变色
      {
        // 旋转都是将不均衡变为相对均衡,然后旋转后的父节点变为黑色,分到叔叔那边的结点变为红色
        // 因为这种情况,爷爷本来就是黑色
        if (parent == grandparent->_left)
        {
          if (cur == parent->_left)
          {
            RotateR(grandparent);
            parent->_col = BLACK;
            grandparent->_col = RED;
          }
          else if (cur == parent->_right)
          {
            RotateL(parent);
            RotateR(grandparent);
            cur->_col = BLACK;
            grandparent->_col = RED;
          }
        }
        else
        {
          if (cur == parent->_left)
          {
            RotateR(parent);
            RotateL(grandparent);
            grandparent->_col = RED;
            cur->_col = BLACK;
          }
          else if (cur == parent->_right)
          {
            RotateL(grandparent);
            grandparent->_col = RED;
            parent->_col = BLACK;
          }
        }
        break;
      }
    }
    _root->_col = BLACK;
    return make_pair(cur, true);
  }
  bool IsValidRBTree()
  {
    Node* pRoot = _root;
    // 空树也是红黑树
    if (nullptr == pRoot)
      return true;
    // 检测根节点是否满足情况
    if (BLACK != pRoot->_col)
    {
      cout << "违反红黑树性质二:根节点必须为黑色" << endl;
      return false;
    }
    // 获取任意一条路径中黑色节点的个数
    size_t blackCount = 0;
    Node* pCur = pRoot;
    while (pCur)
    {
      if (BLACK == pCur->_col)
        blackCount++;
      pCur = pCur->_left;
    }
    // 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
    size_t k = 0;
    return _IsValidRBTree(pRoot, k, blackCount);
  }
  bool _IsValidRBTree(Node* 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->_col)
      k++;
    // 检测当前节点与其双亲是否都为红色
    Node* pParent = pRoot->_parent;
    if (pParent && RED == pParent->_colo && RED == pRoot->_col)
    {
      cout << "违反性质三:没有连在一起的红色节点" << endl;
      return false;
    }
    return _IsValidRBTree(pRoot->_left, k, blackCount) &&
      _IsValidRBTree(pRoot->_right, k, blackCount);
  }
  void Order()
  {
    _Order(_root);
    cout << endl;
  }
  void _Order(Node* root)
  {
    if (root == nullptr)
      return;
    _Order(root->_left);
    cout << root->_kv.first << " ";
    _Order(root->_right);
  }
  void RotateR(Node* parent)
  {
    Node* subL = parent->_left;
    Node* subLR = subL->_right;
    Node* parentParent = parent->_parent;
    subL->_right = parent;
    parent->_parent = subL;
    parent->_left = subLR;
    if (subLR)
      subLR->_parent = parent;
    if (parent == _root)
    {
      _root = subL;
      subL->_parent = nullptr;
    }
    else
    {
      if (parentParent->_left == parent)
      {
        parentParent->_left = subL;
      }
      else if (parentParent->_right == parent)
      {
        parentParent->_right = subL;
      }
      subL->_parent = parentParent;
    }
  }
  void RotateL(Node* parent)
  {
    Node* subR = parent->_right;
    Node* subRL = subR->_left;
    Node* parentParent = parent->_parent;
    subR->_left = parent;
    parent->_parent = subR;
    if (subRL)
      subRL->_parent = parent;
    parent->_right = subRL;
    if (parent == _root)
    {
      _root = subR;
      subR->_parent = nullptr;
    }
    else
    {
      // 先找到 parent 是父亲的左子树还是右子树
      if (parentParent->_left == parent) // 左子树
      {
        parentParent->_left = subR;
      }
      else if (parentParent->_right == parent) // 右子树
      {
        parentParent->_right = subR;
      }
      subR->_parent = parentParent;
    }
  }
private:
  Node* _root = nullptr;
};

MyMap.h

#pragma once
#include"RBTree.h"
namespace zyb
{
  template<typename K, typename T>
  class map
  {
  public:
    struct MapKeyOfT
    {
      const K& operator()(const pair<const K, T>& kv)
      {
        return kv.first;
      }
    };
    typedef typename RBTree<K, pair<const K, T>, MapKeyOfT>::iterator iterator;
    typedef typename RBTree<K, pair<const K, T>, 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();
    }
    T& operator[](const K& key)
    {
      pair<iterator, bool> ret = insert(make_pair(key, T()));
      return ret.first->second;
    }
    pair<iterator, bool> insert(const pair<const K, T>& kv)
    {
      return _t.Insert(kv);
    }
  private:
    RBTree<K, pair<const K, T>, MapKeyOfT> _t;
  };
}

MySet.h

#pragma once
#include"RBTree.h"
namespace zyb
{
  template<typename K>
  class set
  {
  public:
    struct SetKeyOfT
    {
      const K& operator()(const K& key)
      {
        return key;
      }
    };
    typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
    typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
    pair<iterator, bool> insert(const K& key)
    {
      return _t.Insert(key);
    }
    const_iterator begin() const
    {
      return _t.begin();
    }
    const_iterator end() const
    {
      return _t.end();
    }
  private:
    RBTree<K, K, SetKeyOfT> _t;
  };
}

可以使用以下用例对功能进行测试:

#include"RBTree.h"
#include"MyMap.h"
#include"MySet.h"
void test1(const zyb::set<int>& s1)
{
   
  zyb::set<int>::const_iterator it = s1.begin();
  while (it != s1.end())
  {
    cout << *it << " ";
    ++it;
  }
  cout << endl;
}
void  test2(const zyb::map<string, int>& m1)
{          
  zyb::map<string, int>::const_iterator it = m1.begin();
  while (it != m1.end())
  {
    cout << it->first << ":" << it->second << endl;
    ++it;
  }
  cout << endl;
}
int main()
{
  zyb::set<int> s1;
  s1.insert(1);
  s1.insert(2);
  s1.insert(3);
  s1.insert(3);
  s1.insert(5);
  s1.insert(6);
  zyb::map<string, int> m1;
  m1.insert(make_pair("zyb", 1));
  m1.insert(make_pair("jn", 1));
  m1.insert(make_pair("yw", 1));
  test1(s1);
  test2(m1);
  return 0;
}

相关文章
|
3月前
|
编译器 C++ 容器
【C++学习手札】基于红黑树封装模拟实现map和set
【C++学习手札】基于红黑树封装模拟实现map和set
|
6月前
|
存储 编译器 程序员
用同一棵红黑树实现map和set【STL】
用同一棵红黑树实现map和set【STL】
17 0
|
6月前
|
存储 算法 容器
|
1月前
|
存储 编译器 容器
用红黑树封装实现map和set
用红黑树封装实现map和set
14 0
|
5月前
|
存储 编译器 C++
【C++从0到王者】第三十五站:面试官让手撕红黑树,我直接向他秀一手手撕map与set
【C++从0到王者】第三十五站:面试官让手撕红黑树,我直接向他秀一手手撕map与set
41 0
|
2月前
|
存储 编译器 Serverless
用C++实现一个哈希桶并封装实现 unordered_map 和 unordered_set
用C++实现一个哈希桶并封装实现 unordered_map 和 unordered_set
|
4月前
|
安全 编译器 测试技术
C++【一棵红黑树封装 set 和 map】
C++【一棵红黑树封装 set 和 map】
34 0
|
4月前
|
存储 C++ 容器
C++模拟实现红黑树并实现对set和map的封装
C++模拟实现红黑树并实现对set和map的封装
70 0
|
3天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
17 3
|
1月前
|
存储 自然语言处理 C++
map和set的简单介绍
map和set的简单介绍
20 1