"我们都无可奈何地选择了,自己的人生。也无可奈何地出演自己拿到的剧本"
(1) set;
①set是什么?
set是一种管理数据的容器,其底层是由红黑树来实现的。
②set的性质:
1.set是按照一定序列存储的容器;
2.set中的元素(value)是唯一的;
3.......
与set相对的就是multiset
很显然,这个容器可以存放相同的数.
(2)map;
①map介绍:
map也是一种关联式容器。和set不同的地方是,map会多一个修饰key的参数value
在map中,这两个值 会被封装到一个pair中,本质上pair 就是一个结构体
②map的性质:
1.和set一样 底层用红黑树实现
2.只能存一个key值。但可以存同一value
3.map支持[]访问
使用map的时候,需要注意的是 他底层去重载的[].
[],返回的是pair中value的值 , 并可以对其进行修改。
与map相对的也有mutltimap:
(3)map/set的底层封装:
重新搭建BRTree框架;
我们在实现红黑树的时候,对于 节点存储的模板为K,V。
怎么能让底层,去同时封装 不同存储类型的容器?!
//template<class K, class V>
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_left(nullptr),
_right(nullptr),
_parent(nullptr),
_data(data),
_col(RED)
{}
};
所以我么你相应对 红黑树的节点 再次泛化。因为它并不知道存储的是什么。
template<class K,class T,class KeyOFT>
struct RBTree
{
typedef RBTreeNode<T> Node;
RBTree()
:_root(nullptr)
{}
Node* _root;
}
我们不妨给红黑树的模板增加一个参数。让T 去决定 节点存什么!
既然T 是未知的,不同的T有不同的比较方法
KeyOFT----->就去弥补 实现不同T数据 的比较。(实现的仿函数)
set/map框架:4
template<class K,class T>
class map
{
public:
struct MapOFT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
private:
RBTree<K, pair<const K, V>, MapOFT> _m;
};
template<class K>
class set
{
public:
struct SetOFT
{
K& operator()(const K& key)
{
return key;
}
};
private:
RBTree<K, K, SetOFT> _s;
};
三者关系整理成图就成了这样。 这种设计极为巧妙。
BRtree迭代器封装;
template<class T,class Ref,class Ptr> //这里的迭代器封装和 list 极为相似 所谓的红黑树迭代器 就是指的 红黑树的节点
struct _RBTree_iterator
{
typedef RBTreeNode<T> Node;
typedef _RBTree_iterator<T, Ref,Ptr> Self;
_RBTree_iterator(Node* node)
:_node(node)
{}
Node* _node;
//opertor*
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
//难点;
//set/map走的是一个 中序
Self& operator++()
{
//此时_node 一定是最左节点
if (_node->_right)
{
//此时如果不为空
//证明右边还需要访问;
Node* left = _node->_right;
while (left->_left)
{
left = left->_left;
}
//此时找到 不为空的 右边的 第一个左边给 _node
_node = left;
}
else
{
//由node出发
//找到 右不为空的 父节点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_right)
{
cur = cur->_parent;
parent = parent->_parent;
}
//下一次进来 就是去访问 _node 右根
_node = parent;
}
return *this;
}
//右子树 根 左子树
Self& operator--()
{
if (_node->_left)
{
Node* right = _node->_left;
while (right->_right)
{
right = right->_right;
}
_node = right;
}
else
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
};
operator++;
operator--;
RBTree封装迭代器+set/map使用:
template<class K,class T>
class map
{
public:
struct MapOFT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
//去红黑树 里找到 被封装好的 迭代器
//此时要添加typename 因为迭代器实例化要在后面才进行
// 这里要让编译器 这是个类
typedef typename RBTree<K, pair<const K, V>, MapOFT>:: iterator iterator;
iterator begin()
{
return _m.begin();
}
iterator end()
{
return _m.end();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _m.insert(kv);
}
private:
RBTree<K, pair<const K, V>, MapOFT> _m;
};
template<class K>
class set
{
public:
struct SetOFT
{
const K& operator()(const K& key)
{
return key;
}
};
typedef typename RBTree<K, K, SetOFT> ::iterator iterator;
iterator begin()
{
return _s.begin();
}
iterator end()
{
return _s.end();
}
pair<iterator, bool> insert(const K& key)
{
return _s.insert(key);
}
private:
RBTree<K, K, SetOFT> _s;
};
封装完成,我们就先拿来用一用;
map/set大致的玩法 行得通。
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key,V()));
return (ret.first)->second;
}
当然不能忘了map 重载的[];
(4)反向迭代器:
这里的反向迭代器,并非来自迭代器萃取。而是由正向迭代器构造出来的。
template<class Iterator>
struct _RBTree_Reverse_iterator
{
//这里只设置了一个 模板参数
//因为 反向迭代器 可以借用正向迭代器的 其他两个模板参数
//同样这是 内置类型的模板 需要typename
typedef typename Iterator::reference Ref;
typedef typename Iterator::pointer Ptr;
typedef _RBTree_Reverse_iterator<Iterator> Self;
Iterator _it;
};
template<class Iterator>
struct _RBTree_Reverse_iterator
{
//这里只设置了一个 模板参数
//因为 反向迭代器 可以借用正向迭代器的 其他两个模板参数
//同样这是 内置类型的模板 需要typename
typedef typename Iterator::reference Ref;
typedef typename Iterator::pointer Ptr;
typedef _RBTree_Reverse_iterator<Iterator> Self;
Iterator _it;
//拿正向 迭代器初始化
_RBTree_Reverse_iterator(Iterator it)
:_it(it)
{}
//operator*
Ref& operator*()
{
return *_it;
}
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
bool operator!=(const Self& s) const
{
return _it != s._it;
}
bool operator==(const Self& s) const
{
return _it == s._it;
}
Ptr operator->()
{
return _it.operator->();
}
};
本篇也就到此为止。
感谢你的阅读
祝你好运~