set和map的封装(C++)
目录
1、前言
2、通过源码进行分析
3、泛型红黑树
3.1红黑树的节点
3.2红黑树的框架
3.3set的框架
3.4map的模版
3.5仿函数
4、迭代器
4.1迭代器的定义
4.2解引用
4.3成员访问操作符
4.4迭代器的等于和不等于
4.5迭代器的++重载
4.6迭代器的--重载
4.7红黑树的迭代器
4.8set的迭代器
4.9map的迭代器
5、总代码
5.1set的代码
5.2map的代码
5.3红黑树的代码
1、前言
在标准库中set和map的底层是通过红黑树实现的。但set是key类型的容器,而map是<key,value>类型的容器,那我们是用key和<key,value>的两棵树分别去实现set和map,还是只需要用一棵树去实现呢?
2、通过源码进行分析

从上面的源码中我们可以看到:set和map中的模版参数都包含key_type和value_type,但在set中这两个参数的本质都是key,而在map中key_type和value_type却分别代表着key和pair
通过红黑树节点所存的数据类型我们可以清楚地知道这棵树是set还是map是由value_type来控制的,因此一棵泛型结构的红黑树,通过不同实例化参数分别构造set和map
3、泛型红黑树
3.1红黑树的节点
enum Color
{Red,Black
};template<class T> //使用模版参数,通过实例化确定里面存储的是key还是pair
struct RBTreeNode
{RBTreeNode(const T& val = T(),Color col = Red):_parent(nullptr),_left(nullptr),_right(nullptr),_val(val),_col(col){ }RBTreeNode* _parent;RBTreeNode* _left;RBTreeNode* _right;T _val;Color _col;
};
3.2红黑树的框架
template<class K, class T>
class RBTree
{typedef RBTreeNode<T> Node; //对于模版参数T,它可以为Key也可以是pair,通过具体的实例化来确定是set还是map
private:Node* _root = nullptr;
};
3.3set的框架
template<class K>
class set
{
public:
private:RBTree<K, K> _t; //set传给泛型红黑树的就是<K,K>
};
3.4map的模版
template<class K,class V>
class map
{
public:
private:RBTree<K, pair<const K, V>> _t; //map传给泛型红黑树的就是<K,pair<K,V>>
};
3.5仿函数
由于set和map是通过泛型红黑树来进行实现的,它的底层也是个搜索树,因此它需要比较大小,对于set,它是个key类型可以直接进行比较,但是对于map,它却是个pair<K,V>类型,虽然库中写了pair的比较,但却并不符合我们的需要,我们需要通过pair的first来比较大小,因此我们需要写一个仿函数来帮助我们解决这一问题,因此该泛型红黑树需要第三个模版参数来接受set和map所对应的仿函数,代码如下:
红黑树的框架:
template<class K, class T, class KeyofT> //第三个模版参数从T中提取key
class RBTree
{typedef RBTreeNode<T> Node;
private:Node* _root = nullptr;
};
set加入仿函数后的框架:
template<class K>
class set
{
public:struct SetKeyofT{const K& operator()(const K& key) //对于set来说仅仅是个形式{return key;}};
private:RBTree<K, K, SetKeyofT> _t;
};
map加入仿函数后的框架:
template<class K,class V>
class map
{
public:struct MapKeyofT{const K& operator()(const pair<K, V>& data) //对于map需要提取key(即pair的first)进行比较{return data.first;}};
private:RBTree<K, pair<const K, V>, MapKeyofT> _t;
};
因此我们的红黑树在查找部分就可以直接通过仿函数来实现了,代码如下:
Node* parent = nullptr;
Node* cur = _root;
KeyofT kot;
while (cur)
{parent = cur;if (kot(val) > kot(cur->_val)){cur = cur->_right;}else if (kot(val) < kot(cur->_val)){cur = cur->_left;}else{return false;}
}
cur = new Node(val);
if (kot(cur->_val) > kot(parent->_val))
{parent->_right = cur;
}
else
{parent->_left = cur;
}
cur->_parent = parent;
4、迭代器
4.1迭代器的定义
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{typedef RBTreeNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){ }
};
4.2解引用
Ref operator*()
{return _node->_val;
}
4.3成员访问操作符
Ptr operator->()
{return &_node->_val;
}
4.4迭代器的等于和不等于
bool operator!=(const Self& s)
{return _node != s._node;
}bool operator==(const Self& s)
{return _node == s._node;
}
4.5迭代器的++重载
- 右不为空时,此时++就需要去找右子树的最左节点
- 右为空时,此时已经走过了左树,且根节点就是当前节点,因此需要向上走去找孩子是父亲左树的那个祖先(即cur == parent->left)
Self& operator++()
{if (_node->_right) //右存在,则下一个节点就是右子树的最左节点{Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else //右不存在{//左 根 右Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur) //右不存在,当前为根,左边已经走过,因此需要向上走,直到未走过的根节点//而这个根节点parent和cur的关系为parent->_left == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;
}
4.6迭代器的--重载
- 左存在时,需要去找左子树的最右节点
- 左不存在时,右走过,当前为根,因此需要向上走,直到走到孩子是父亲右的祖先,即这个父节点parent和cur的关系为parent->_right == cur
Self& operator--()
{// 左 根 右if (_node->_left) //左存在,当前为根,下一个节点就是左子树的最右节点{Node* cur = _node->_left;while (cur->_right){cur = cur->_right;}_node = cur;}else //左不存在{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur)//左不存在,右走过,当前为根,因此需要向上走,直到找到孩子是父亲右的祖先//而这个根节点parent和cur的关系为parent->_right == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;
}
4.7红黑树的迭代器
typedef __RBTreeIterator<T, T&, T*> iterator;
typedef __RBTreeIterator<T, const T&, const T*> const_iterator;
iterator begin()
{Node* cur = _root;while (cur->_left){cur = cur->_left;}return iterator(cur);
}
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);
}
4.8set的迭代器
typedef typename RBTree<K, K, SetKeyofT>::const_iterator iterator; //set的key不能修改,因此都是const迭代器
typedef typename RBTree<K, K, SetKeyofT>::const_iterator const_iterator;iterator begin()const
{return _t.begin();
}
iterator end()const
{return _t.end();
}
4.9map的迭代器
template<class K,class V>
class map
{
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();}
private:RBTree<K, pair<const K, V>, MapKeyofT> _t; //map的key不可以修改,value可以修改,因此需要const修饰key
};
5、总代码
5.1set的代码
namespace asd //避免与库中的set冲突,需要命名空间
{template<class 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;iterator begin()const{return _t.begin();}iterator end()const{return _t.end();}bool insert(const K& key){return _t.insert(key);}private:RBTree<K, K, SetKeyofT> _t;};
}
5.2map的代码
namespace ads
{template<class K,class V>class map{public:struct MapKeyofT{const K& operator()(const pair<K, V>& data){return data.first;}};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();}bool insert(const pair<const K, V>& data){return _t.insert(data);}private:RBTree<K, pair<const K, V>, MapKeyofT> _t;};
}
5.3红黑树的代码
enum Color
{Red,Black
};
template<class T>
struct RBTreeNode
{RBTreeNode(const T& val = T(),Color col = Red):_parent(nullptr),_left(nullptr),_right(nullptr),_val(val),_col(col){ }RBTreeNode* _parent;RBTreeNode* _left;RBTreeNode* _right;T _val;Color _col;
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{typedef RBTreeNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){ }Ref operator*(){return _node->_val;}Ptr operator->(){return &_node->_val;}Self& operator++(){if (_node->_right) //右存在,则下一个节点就是右子树的最左节点{Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else //右不存在{//左 根 右Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur) //右不存在,当前为根,左边已经走过,因此需要向上走,直到未走过的根节点,//而这个根节点parent和cur的关系为parent->_left == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self& operator--(){// 左 根 右if (_node->_left) //左存在,当前为根,下一个节点就是左子树的最右节点{Node* cur = _node->_left;while (cur->_right){cur = cur->_right;}_node = cur;}else //左不存在{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur)//左不存在,右走过,当前为根,因此需要向上走,直到未走过的节点,//而这个根节点parent和cur的关系为parent->_right == cur{cur = parent;parent = cur->_parent;}_node = parent;}return *this;}bool operator!=(const Self& s){return _node != s._node;}bool operator==(const Self& s){return _node == s._node;}
};template<class K, class T, class KeyofT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef __RBTreeIterator<T, T&, T*> iterator;typedef __RBTreeIterator<T, const T&, const T*> const_iterator;iterator begin(){Node* cur = _root;while (cur->_left){cur = cur->_left;}return iterator(cur);}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);}bool insert(const T& val){if (_root == nullptr){_root = new Node(val);_root->_col = Black;return true;}else{Node* parent = nullptr;Node* cur = _root;KeyofT kot;while (cur){parent = cur;if (kot(val) > kot(cur->_val)){cur = cur->_right;}else if (kot(val) < kot(cur->_val)){cur = cur->_left;}else{return false;}}cur = new Node(val);if (kot(cur->_val) > kot(parent->_val)){ parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//往下都是对红黑树的调整以及检查是否是红黑树的代码while (parent && parent->_col == Red){Node* grandparent = parent->_parent;if (grandparent->_left == parent){Node* uncle = grandparent->_right;if (uncle && uncle->_col == Red){grandparent->_col = Red;parent->_col = uncle->_col = Black;//继续向上检查cur = grandparent;parent = cur->_parent;}else //(uncle == nullptr || uncle->_col == Black){//cur是parent的左孩子,单旋调整if (cur == parent->_left){RotateR(grandparent);parent->_col = Black;grandparent->_col = Red;}else //cur是parent的右孩子,双旋调整{RotateL(parent);RotateR(grandparent);cur->_col = Black;grandparent->_col = Red;}break;}}else{Node* uncle = grandparent->_left;if (uncle && uncle->_col == Red){grandparent->_col = Red;parent->_col = uncle->_col = Black;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_col = Black;grandparent->_col = Red;}else{RotateR(parent);RotateL(grandparent);cur->_col = Black;grandparent->_col = Red;}break;}}}_root->_col = Black; return true;}}bool IsBalance(){return _IsBalance(_root);}int Height(){return _Height(_root);}
private:bool CheckColour(Node* root, int blacknum, int benchmark){if (root == nullptr){if (blacknum != benchmark)return false;return true;}if (root->_col == Black){++blacknum;}if (root->_col == Red && root->_parent && root->_parent->_col == Red){cout << root->_val << "出现连续红色节点" << endl;return false;}return CheckColour(root->_left, blacknum, benchmark)&& CheckColour(root->_right, blacknum, benchmark);}bool _IsBalance(Node* root){if (root == nullptr)return true;if (root->_col != Black){return false;}// 基准值int benchmark = 0;Node* cur = _root;while (cur){if (cur->_col == Black)++benchmark;cur = cur->_left;}return CheckColour(root, 0, benchmark);}int _Height(Node* root){if (root == nullptr)return 0;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}void RotateR(Node* parent){Node* subl = parent->_left;Node* sublr = subl->_right;Node* pparent = parent->_parent;parent->_left = sublr;if (sublr)sublr->_parent = parent;subl->_right = parent;parent->_parent = subl;if (_root == parent){_root = subl;subl->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = subl;}else{pparent->_right = subl;}subl->_parent = pparent;}}void RotateL(Node* parent){Node* subr = parent->_right;Node* subrl = subr->_left;parent->_right = subrl;subr->_left = parent;Node* pparent = parent->_parent;parent->_parent = subr;if (subrl)subrl->_parent = parent;if (_root == parent){_root = subr;subr->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = subr;}else{pparent->_right = subr;}subr->_parent = pparent;}}Node* _root = nullptr;
};
