文章目录
- 一、STL中set与map的源码
- 二、 红黑树结点的意义
- 三、仿函数的妙用
- 四、set,map定义迭代器的区别
- 五、map,set迭代器的基本操作:
- 1.begin() end()
- 2.operator++
- 3.operator--
- 六、迭代器拷贝构造特殊处理
- 7.源码
- RBTree.h
- 2.MyMap.h
- 3.MySet.h
一、STL中set与map的源码
因为关联式容器中存储的是<key, value>的键值对,因此k为key的类型,
ValueType: 如果是map,则为pair<K, V>; 如果是set,则为k
KeyOfValue: 通过value来获取key的一个仿函数类
二、 红黑树结点的意义
我们知道map,和set需要用红黑树来实现,但我们map的数据类型是键值对pair<K,V>类型,key的数据类型是单纯的K类型,那如何写出一个通用的红黑树模板呢?
template<class T>//关键之处
struct RBTreeNode {RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Color _col;//结点颜色T _data;RBTreeNode(const T&data):_left(nullptr),_right(nullptr),_parent(nullptr),_col(RED),_data(data){}
};
我们这里把pair<K,V>看成一个整体,我们设计模板的时候就不需要考虑是不是键值对类型,需不需要多传一个模板参数的问题,达到了普适性。
在map中,T传pair<K,V>类型
在set中,T传K类型
三、仿函数的妙用
我们value_type类型用模板参数T代替之后,这个时候就会衍生一个问题,我T可能为键值对类型,我键值对之间怎么比较呢?
例如:T t1与T t2两个变量,我们肯定不能直接比较,肯定要依据他们的键值大小进行比较,所以我们需要自己写一个用于比较的函数,这个时候仿函数刚好能发挥这个用处,可以作为模板参数传入自己写的比较函数
取出他们的键,让他们进行比较,这里set也这样写是为了配合map,因为两者都用的一个红黑树模板
struct SetKeyOfT {const K& operator()(const K&key) {return key;}};struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};
示例:红黑树中Find函数的实现:
Node* Find(const K& key){Node* cur = _root;KeyOfT kot;//KeyOfT为仿函数的类型//写好仿函数后先实例化出来while (cur){if (kot(cur->_data) < key){cur = cur->_right;}else if (kot(cur->_data) > key){cur = cur->_left;}else{return cur;}}return nullptr;}
四、set,map定义迭代器的区别
因为set插入进去后,set的值不可以被修改,为了实现这一操作我们可以在迭代器上下手
//typename是告诉编译器这里后面跟的是类型不是对象,以免编译器报错
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
//既然不可修改,那我就都用const类型的迭代器
在map中,我们是键不可修改,而其所对应的值可被修改,所以不能用set的那种操作,可以在传模板参数的时候动手脚,传pair的时候直接把K改为const类型
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;
五、map,set迭代器的基本操作:
1.begin() end()
iterator begin(){Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return iterator(leftMin);}iterator end(){return iterator(nullptr);}const_iterator begin() const{Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return const_iterator(leftMin);}const_iterator end() const{return const_iterator(nullptr);}
2.operator++
1.cur的右不为空访问右树的最左结点
2.cur的右为空,找到cur是parent左子树的位置,此时parent的位置就是++后的位置
Self& operator++(){if (_node->_right){// 右树的最左节点(最小节点)Node* subLeft = _node->_right;while (subLeft->_left){subLeft = subLeft->_left;}_node = subLeft;}else{Node* cur = _node;Node* parent = cur->_parent;// 找孩子是父亲左的那个祖先节点,就是下一个要访问的节点while (parent && cur == parent->_right){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
3.operator–
–就与++反着来
1.左不为空,找到左树的最右结点
2.左为空,找到cur是parent右的那个结点,此时parent的位置就是–之后的位置
Self& operator--(){if (_node->_left){Node* subRight = _node->_left;while (subRight->_right){subRight = subRight->_right;}_node = subRight;}else{// 孩子是父亲的右的那个节点Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
六、迭代器拷贝构造特殊处理
template<class T, class Ptr, class Ref>
struct __TreeIterator
{typedef RBTreeNode<T> Node;typedef __TreeIterator<T, Ptr, Ref> Self;typedef __TreeIterator<T, T*, T&> Iterator;__TreeIterator(const Iterator& it):_node(it._node){}Node* _node;__TreeIterator(Node* node):_node(node){}};
1.当我们Ptr与Ref分别实例化为T与T&的时候,__TreeIterator(const Iterator& it)就是一个拷贝构造函数,因为Iterator与Self类型相同
2.当我们Ptr与Ref分别实例化为const T与const T&的时候,__TreeIterator(const Iterator& it)是一个构造,支持普通迭代器构造const类型的迭代器因为Self为const类型,Iterator为普通类型
这里支持用普通迭代器去构造const类型的迭代器,就可以满足我们set的插入功能的实现
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){
pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
//这里RBTree里面的iterator类型为普通迭代器类型,而我们返回值里面的pair中的iterator为const类型,
//所以要想返回必须先把RBTree中的iterator变为const类型,这个时候可以拷贝构造
//让普通迭代器变为const类型的迭代器return pair<iterator, bool>(ret.first, ret.second);}
7.源码
这里会涉及到红黑树的一些变色问题,之前的博客有提到过【C++】红黑树插入操作实现以及验证红黑树是否正确
需要的小伙伴可以去看一下
RBTree.h
#pragma once
#include<iostream>
using namespace std;enum Color {RED,BLACK
};template<class T>//关键之处
struct RBTreeNode {RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Color _col;//结点颜色T _data;RBTreeNode(const T&data):_left(nullptr),_right(nullptr),_parent(nullptr),_col(RED),_data(data){}
};template<class T, class Ptr, class Ref>
struct __TreeIterator
{typedef RBTreeNode<T> Node;typedef __TreeIterator<T, Ptr, Ref> Self;typedef __TreeIterator<T, T*, T&> Iterator;__TreeIterator(const Iterator& it):_node(it._node){}Node* _node;__TreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node != s._node;}Self& operator--(){if (_node->_left){Node* subRight = _node->_left;while (subRight->_right){subRight = subRight->_right;}_node = subRight;}else{// 孩子是父亲的右的那个节点Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}Self& operator++(){if (_node->_right){// 右树的最左节点(最小节点)Node* subLeft = _node->_right;while (subLeft->_left){subLeft = subLeft->_left;}_node = subLeft;}else{Node* cur = _node;Node* parent = cur->_parent;// 找孩子是父亲左的那个祖先节点,就是下一个要访问的节点while (parent && cur == parent->_right){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
};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;iterator begin(){Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return iterator(leftMin);}iterator end(){return iterator(nullptr);}const_iterator begin() const{Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return const_iterator(leftMin);}const_iterator end() const{return const_iterator(nullptr);}Node* Find(const K& key){Node* cur = _root;KeyOfT kot;//KeyOfT为仿函数的类型//写好仿函数后先实例化出来while (cur){if (kot(cur->_data) < key){cur = cur->_right;}else if (kot(cur->_data) > key){cur = cur->_left;}else{return cur;}}return nullptr;}pair<iterator, bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root), true);}Node* parent = nullptr;Node* cur = _root;KeyOfT kot;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(iterator(cur), false);}}cur = new Node(data);cur->_col = RED;Node* newnode = cur;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;// u存在且为红if (uncle && uncle->_col == RED){// 变色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 继续向上处理cur = grandfather;parent = cur->_parent;}else // u不存在 或 存在且为黑{if (cur == parent->_left){// g// p// cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// p// cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else // parent == grandfather->_right{Node* uncle = grandfather->_left;// u存在且为红if (uncle && uncle->_col == RED){// 变色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 继续向上处理cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){// g// p// cRotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else{// g// p// cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(iterator(newnode), true);}void RotateL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if (curleft){curleft->_parent = parent;}cur->_left = parent;Node* ppnode = parent->_parent;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;}}void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright)curright->_parent = parent;Node* ppnode = parent->_parent;cur->_right = parent;parent->_parent = cur;if (ppnode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}}
private:Node* _root = nullptr;
};
2.MyMap.h
#pragma once
#include"RBTree.h"
namespace bit {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();}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;};}
3.MySet.h
#pragma once
#include"RBTree.h"namespace bit {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;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);return pair<iterator, bool>(ret.first, ret.second);}private:RBTree<K, K, SetKeyOfT> _t;};
}