这两个容器底层都是对红黑树的封装,因此需要先看一下红黑树结构部分的底层源码:
//树结点的定义:
struct __rb_tree_node_base
{
typedef __rb_tree_color_type color_type;
typedef __rb_tree_node_base* base_ptr;
color_type color;
base_ptr parent;
base_ptr left;
base_ptr right;
};
//子类继承
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
typedef __rb_tree_node<Value>* link_type;
//存储有效数据
Value value_field;
};
//红黑树部分成员
template <class Key, class Value, class KeyOfValue, class Compare,
class Alloc = alloc>
class rb_tree {
protected:
typedef __rb_tree_node<Value> rb_tree_node;
public:
typedef Key key_type;
typedef Value value_type;
typedef rb_tree_node* link_type;
protected:
size_type node_count; // keeps track of size of tree
link_type header;
Compare key_compare;
}
可以发现红黑树的结点中存储的元素类型只与第二个模板参数Value有关,对于set而言value是Key,对于map而言value是pair
Key也需要传递,树中有些接口的实现需要用到,比如find等。
set底层结构的部分构成:
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
// typedefs:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
typedef Compare value_compare;
private:
///红黑树
typedef rb_tree<key_type, value_type,
identity<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing set
}
set是K模型,因此key_type是Key,value_type也是Key,实例化后树中要存储的元素类型也是Key类型。
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
// typedefs:
typedef Key key_type;
typedef T data_type;
typedef T mapped_type;
typedef pair<const Key, T> value_type;
typedef Compare key_compare;
private:
typedef rb_tree<key_type, value_type,
select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing map
}
对于map而言,key_type是Key,而value_type则是一个pair
由于map和set用到的是同一个类模板,因此红黑树类模板的设计要支持泛型。
树结点的定义:
template<class T>
struct RBTreeNode {
RBTreeNode(const T& data)
:_data(data), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED)
{ }
T _data;
enum Color _col;
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
};
对于set而言,T就是key,而对于map而言T为pair
树的定义:
template<class K, class T, class KeyOfT>
//第三个模板参数为仿函数
//作用是取出date中的key来进行比较
//插入元素时要按照key的关键码进行比较选择合适的插入位置
//但是插入的是data,对于map来说data无法按照预期进行比较
//因为data的类型T为pair,需要取出data中的key
//而对于set而言,可以用data比,因为data的类型T就是key
//不过为了统一处理,都通过仿函数来取出key
class RBTree {
typedef RBTreeNode<T> Node;
public:
typedef Iterator<T> iterator;
public:
pair<iterator, bool> insert(const T& data) {
if (!_root) {
_root = new Node(data);
_root->_col = BLACK;
return pair<iterator, bool>(_root, true);
}
Node* cur = _root;
Node* parent = nullptr;
//定义仿函数对象
KeyOfT kot;
while (cur) {
//取出data中的key进行比较
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 pair<iterator, bool>(cur, false);
}
}
cur = new Node(data);
pair<iterator, bool> ret(cur, true);
if (kot(parent->_data) < kot(data)) {
parent->_right = cur;
}
else {
parent->_left = cur;
}
cur->_parent = parent;
//parent为红需要一直往上调整
while (parent && parent->_col == RED) {
Node* grandpa = parent->_parent;
if (grandpa->_left == parent) {
Node* uncle = grandpa->_right;
//叔叔存在且为红
if (uncle && uncle->_col == RED) {
//把父亲和叔叔染黑
//爷爷染红继续往上调整
parent->_col = uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
//叔叔不存在或者存在且为黑
else {
//单纯的一边高(直线)单旋
if (cur == parent->_left) {
rotateRight(grandpa);
parent->_col = BLACK;
cur->_col = grandpa->_col = RED;
}
//折线情况需要双旋
else {
rotateLeft(parent);
rotateRight(grandpa);
cur->_col = BLACK;
parent->_col = grandpa->_col = RED;
}
break;
}
}
//同样的逻辑
else {
Node* uncle = grandpa->_left;
if (uncle && uncle->_col == RED) {
parent->_col = uncle->_col = BLACK;
grandpa->_col = RED;
cur = grandpa;
parent = cur->_parent;
}
else {
if (parent->_right == cur) {
rotateLeft(grandpa);
grandpa->_col = cur->_col = RED;
parent->_col = BLACK;
}
else {
rotateRight(parent);
rotateLeft(grandpa);
parent->_col = grandpa->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_root->_col = BLACK;
return ret;
}
private:
Node* _root = nullptr;
};
set:
template<class K>
class set {
struct SetKeyOfT {
const K& operator()(const K& key) {
return key;
}
};
//显式传递仿函数
typedef RBTree<K, const K, SetKeyOfT> rbt;
private:
rbt t;
};
map:
template<class K, class T>
class map {
//内部类
struct MapKeyOfT {
const K& operator()(const pair<const K, T>& key) {
return key.first;
}
};
typedef RBTree<K, pair<const K, T>, MapKeyOfT> rbt;
private:
rbt t;
};
仿函数的作用在于统一取出结点中的Key进行比较。
map和set通过迭代器进行遍历时,本质是对这颗树进行中序遍历,得到的结果是有序的,因此迭代器中最重要的功能是++和–的实现逻辑,对于++,本质是中序遍历时的下一个位置,具体可分为两步:
self& operator++() {
//右子树不为空,去找右树的最左结点
if (_it->_right) {
Node* leftMin = _it->_right;
while (leftMin && leftMin->_left) {
leftMin = leftMin->_left;
}
_it = leftMin;
}
//为空
//去找孩子是父亲的左的那个根结点
else {
Node* cur = _it;
Node* parent = cur->_parent;
while (parent && cur == parent->_right) {
cur = cur->_parent;
parent = parent->_parent;
}
_it = parent;
}
return *this;
}
由于set中的元素不允许修改,所以set的普通和const迭代器都是树中的const迭代器:
但是这种设计会出现一个问题:
会导致类型不匹配,这是因为树的insert返回值pair中的迭代器类型是普通迭代器,而set中的迭代器的类型是const类型,普通迭代器无法构造const迭代器,所以会报错,解决方法为:设计一个支持普通迭代器转化为cons迭代器的构造函数。
对于实例化const迭代器类型的模板类而言,该函数是构造函数,而对于实例化普通迭代器类型的模板类而言,该函数是拷贝构造,通过该函数即可解决上述问题。
map的普通和const迭代器的设计则与其它容器是类似的,只是不管是普通还是const迭代器都无法对key进行修改,而value是否能修改则取决于迭代器的具体类型。
迭代器整体实现代码:
template <class T, class Ref, class Ptr>
struct Iterator {
typedef Iterator<T, Ref, Ptr> self;
typedef Iterator<T, T&, T*> iterator;
typedef Iterator<T, const T&, const T*> const_iterator;
typedef RBTreeNode<T> Node;
Iterator(const iterator& it) :_it(it._it)
{ }
Iterator(Node* it) :_it(it)
{ }
bool operator!=(const self& s) const {
return _it != s._it;
}
bool operator==(const self& s) const {
return !(*this != s);
}
self& operator++() {
if (_it->_right) {
Node* leftMin = _it->_right;
while (leftMin && leftMin->_left) {
leftMin = leftMin->_left;
}
_it = leftMin;
}
else {
Node* cur = _it;
Node* parent = cur->_parent;
while (parent && cur == parent->_right) {
cur = cur->_parent;
parent = parent->_parent;
}
_it = parent;
}
return *this;
}
self& operator--() {
if (_it->_left) {
Node* leftMax = _it->_left;
while (leftMax && leftMax->_right) {
leftMax = leftMax->_right;
}
_it = leftMax;
}
else {
Node* cur = _it;
Node* parent = cur->_parent;
while (parent && cur == parent->_left) {
cur = cur->_parent;
parent = parent->_parent;
}
_it = parent;
}
return *this;
}
Ref operator*() {
return _it->_data;
}
Ptr operator->() {
return &_it->_data;
}
Node* _it;
};
set:
#include "RBTree.h"
namespace lzh {
template<class K>
class set {
struct SetKeyOfT {
const K& operator()(const K& key) {
return key;
}
};
typedef RBTree<K, K, SetKeyOfT> rbt;
public:
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
public:
iterator begin() const {
return _t.begin();
}
iterator end() const {
return _t.end();
}
pair<iterator, bool> insert(const K& data) {
pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> p = _t.insert(data);
return pair<iterator, bool>(p.first, p.second);
}
private:
rbt _t;
};
};
map:
#include "RBTree.h"
namespace lzh {
template<class K, class T>
class map {
struct MapKeyOfT {
const K& operator()(const pair<const K, T>& key) {
return key.first;
}
};
typedef RBTree<K, pair<const K, T>, MapKeyOfT> rbt;
public:
typedef typename RBTree<K, pair<const K, T>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, T>, MapKeyOfT>::const_iterator const_iterator;
public:
iterator begin() {
return t.begin();
}
iterator end() {
return t.end();
}
pair<iterator, bool> insert(const pair<const K, T>& data) {
return t.insert(data);
}
T& operator[](const K& k) {
return insert({ k, T() }).first->second;
}
private:
rbt t;
};
};