STL容器分为两类, 一类是序列式容器(vector、list、string等),另一类是关联式容器(map、set、unordered_map、unordered_set)。
两者有何区别呢?
1、序列式容器内部存储的是元素本身。 而关联式容器内部存储的是键值对。
2、底层实现的算法不同。 序列式容器底层实现的数据结构为线性的(线性表、链表等), 而关联式容器底层实现的数据结构为非线性的(树)。
(ps:说这些是为了唤醒大家数据结构方面的联想!)
准确来讲这个树是红黑树。
基于上次写的红黑树那节文章代码, 我做了一些修正和添加了一些新接口实现了一些简单的map、set功能。
有兴趣的大佬可以光顾下本人红黑树篇章, 或阅读其他大佬的文章!
分析:
1)map类内部调用红黑树传参
RBTree<K, pair<K, V>, MapKeyOfValue> _rb;
set内部调用红黑树传参
RBTree<K, K, SetKeyOfValue> _rb;
这个是红黑树的泛型
template<class K, class V, class KeyOfValue>
对于map:红黑树中K是k值,V值是一个键值对。
对于set: 红黑树中K,V都是K值。
第三个参数是一个仿函数, 这个仿函数是是关键。
通过它可以得出对应map、set的V值。
(不然双方调用同一份代码, key值没什么说的, 但是V值不一样出现错误!)
2)其次map、set容器中insert、迭代器接口都是封装了红黑树中的。
3)关于迭代器, 采用一个类封装。和list容器相似。
这块关于迭代的++, --操作,会遵循一定的原则。
对于++, 判断该结点是否存在右子树,如果存在右子树,
那么右子树的最左结点就是下一个结点,也就是迭代器指向的结点
如果不存在右子树,就需要向上回溯!
迭代器--操作同理
4)map容器中[]运算符重载,内部时调用insert接口实现的, map中[]既可以修改、又可以插入。 set不支持[]运算符重载!
实现其实是调用了红黑树insert接口
pair<iterator, bool> insert(const V& value)
operator[]重载包含了封装了insert接口, 请看下面操作!
return ((*(_rb.insert(make_pair(key, V())).first)).second);
简单分析一下:上面的可以分以下3部分:
pair<iterator, bool> ret = _rb.insert(make_pair(key, V())); //调用inset接口的返回值
iterator it = ret.first; //取到键值对中迭代器
return (*it).second; //迭代器解引用会获取到键值对, map在传入红黑树的V值是pair<K,V>键值对, 然后取second就是操作的对象。
1)红黑树的insert()返回值是一个pair<iterator, bool>键值对,
ret是得到insert的返回值。因此ret是一个pair<iterator, bool>类型。
2)it 是得到ret键值对的first成员, 对应就是iterator类
3)对it取*, 实质上调用了iterator类中*运算符重载, 会得到存入的键值对类型,
取second会得到存入键值对的V值, 也就是我们要操作的元素。
5)map的迭代器是非non-const类型, set迭代器是const类型。
源码:
#include<iostream>
#include<utility>
#include<time.h>
using namespace std;
enum COLOR {
BLACK,
RED
};
//结点只关心V
template<class V>
struct RBNode {
//定义RB树的节点信息
RBNode<V>* _left;
RBNode<V>* _right;
RBNode<V>* _parent;
V _value;
COLOR _color; //定义一个枚举变量
RBNode(const V& value = V()) //相当传递一个匿名的对象
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _value(value) //pair类中自动赋值
, _color(RED)
{
}
};
//封装迭代器类
template<class V>
struct RBIterator {
typedef RBIterator<V> Self;
typedef RBNode<V> Node;
typedef Node* pNode;
pNode _node;
RBIterator(pNode node) {
_node = node;
}
V& operator*() {
return _node->_value;
}
V* operator->() {
return &_node->_value;
}
bool operator!= (const Self& it) {
return _node != it._node;
}
//前置++接口
Self& operator++() {
if (_node->_right) {
pNode cur = _node->_right;
while (cur->_left) {
cur = cur->_left;
}
_node = cur;
}
else {
//这块有问题
pNode parent = _node->_parent;
//继续往上回溯
while (_node == parent->_right) {
_node = parent;
parent = parent->_parent;
}
//特殊情况 - 根节点无右子树
//if(_node->right != parent)如果不加这个条件,就_node = parent;
//如果是无右子树的情况 - parent = _header 而 _header->_right == _root
//满足上述循环, 则_node = _header, parent = _root;
//但是下面又走_node = parent = root,这样永远不能到end(_header)
//因此需要加下面条件 - 防止根节点无右子树造成的死循环!
if (_node->_right != parent)
_node = parent;
}
return *this;
}
//前置--
Self& operator--() {
if (_node->_left) {
//存在左子树
_node = _node->_left;
while (_node->_right) {
_node = _node->_right;
}
}
else {
//不存在左子树, 向上回溯
pNode parent = _node->_parent;
while (parent->_left == _node) {
_node = parent;
parent = parent->_parent;
}
//特殊情况 - 根结点无左子树的情况
if (_node->_left != parent) {
_node = parent;
}
}
return *this;
}
};
//传递是3个泛型类型
template<class K, class V, class KeyOfValue>
class RBTree {
public:
typedef RBNode<V> Node;
typedef Node* pNode;
typedef RBIterator<V> iterator; //重命名iterator, 这块迭代器就是一个类。 和list实现很像。
RBTree() {
//无参构造 - 空树
_header = new Node;
_header->_left = _header;
_header->_right = _header;
_header->_parent = nullptr;
}
//iterator begin接口
iterator begin() {
return iterator(_header->_left);
}
iterator end() {
return iterator(_header);
}
iterator cbegin() {
return iterator(_header->_right);
}
iterator cend() {
return iterator(_header);
}
void RotateL(pNode& parent) {
pNode SubR = parent->_right;
pNode SubRL = SubR->_left;
SubR->_left = parent;
parent->_right = SubRL;
pNode pp = parent->_parent;
if (pp != _header) {
if (pp->_left == parent) {
pp->_left = SubR;
}
else {
pp->_right = SubR;
}
}
else {
_header->_parent = SubR;
}
SubR->_parent = pp;
if (SubRL) {
SubRL->_parent = parent;
}
parent->_parent = SubR;
}
void RotateR(pNode& parent) {
pNode SubL = parent->_left;
pNode SubLR = SubL->_right;
SubL->_right = parent;
parent->_left = SubLR;
pNode pp = parent->_parent;
if (pp != _header) {
if (pp->_left == parent) {
pp->_left = SubL;
}
else {
pp->_right = SubL;
}
}
else {
_header->_parent = SubL;
}
SubL->_parent = pp;
if (SubLR) {
SubLR->_parent = parent;
}
parent->_parent = SubL;
}
pair<iterator, bool> insert(const V& value) {
//判断是否为空树
if (_header->_parent == nullptr) {
//创建根节点
pNode root = new Node(value);
root->_color = BLACK; //更改根节点颜色为黑色
//根的父节点 == 头, 头节点的父节点 == 根
root->_parent = _header;
_header->_parent = root;
//头节点的左右节点==根
_header->_left = root;
_header->_right = root;
return make_pair(iterator(root), true);
}
//从根节点开始查找合适位置
pNode cur = _header->_parent;
pNode parent = nullptr;
//通过仿函数对象获取V对应的K
KeyOfValue kov;
//现在有个问题: 如何区分是pair 还是 value。
while (cur) {
parent = cur;
if (kov(cur->_value) == kov(value))
return make_pair(iterator(cur), false);
else if (kov(cur->_value) > kov(value))
cur = cur->_left;
else
cur = cur->_right;
}
cur = new Node(value);
pNode newNode = cur;
if (kov(parent->_value) > kov(cur->_value))
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
//调整阶段
while (cur != _header->_parent && cur->_parent->_color == RED) {
//父亲的节点为红色(红红需要调整,) && 可以判断parent不为根 - 祖父就会存在
parent = cur->_parent;
pNode gfather = parent->_parent;
if (gfather->_left == parent) {
//叔叔节点在右边
pNode uncle = gfather->_right;
if (uncle && uncle->_color == RED) {
//叔叔节点存在, 并且为红
//调整方式1
parent->_color = uncle->_color = BLACK;
gfather->_color = RED;
//继续向上更新
cur = gfather;
}
else {
//叔叔节点存在, 但为黑 or 叔叔不存在
//调整完毕之后对gfather往上的节点无影响, 停止调整
//双旋情况 cur和parent不在同一遍
if (cur == parent->_right) {
RotateL(parent);
swap(parent, cur);
}
RotateR(gfather);
parent->_color = BLACK;
gfather->_color = RED;
//退出
break;
}
}
else if (gfather->_right == parent) {
//叔叔节点在左边
pNode uncle = gfather->_left;
if (uncle && uncle->_color == RED) {
//叔叔节点存在, 并且为红
//调整方式1
parent->_color = uncle->_color = BLACK;
gfather->_color = RED;
//持续往上更新
cur = gfather;
}
else {
//叔叔节点存在, 但为黑 or 叔叔不存在
//调整完毕之后对gfather往上的节点无影响, 停止调整
//双旋 - parent和cur不在一边
if (cur == parent->_left) {
RotateR(parent);
swap(cur, parent);
}
//左旋
RotateL(gfather);
parent->_color = BLACK;
gfather->_color = RED;
//退出
break;
}
}
}
//根节点强转为黑色
_header->_parent->_color = BLACK;
//更新, 更新最左节点和最右节点 - 方便迭代器的设计
pNode leMostNode = LeftMost();
pNode riMostNode = RightMost();
_header->_left = leMostNode;
_header->_right = riMostNode;
return make_pair(iterator(newNode), true);
}
//寻找最左节点
pNode& LeftMost() {
pNode cur = _header->_parent;
if (!cur) {
//无根节点
return _header->_parent;
}
while (cur->_left != nullptr) {
cur = cur->_left;
}
return cur;
}
//寻找最右节点
pNode& RightMost() {
pNode cur = _header->_parent;
if (!cur) {
return _header->_parent;
}
while (cur->_right != nullptr) {
cur = cur->_right;
}
return cur;
}
//中序遍历
void InOrder() {
_InOrder(_header->_parent);
cout << endl;
}
bool isRBTree() {
pNode root = _header->_parent;
//根结点为空
if (!root) {
return false;
}
//根结点为红色
if (root->_color == RED) {
return false;
}
pNode cur = root;
int blackCount = 0;
//统计最左路径下黑色结点的个数
while (cur) {
if (cur->_color == BLACK) {
blackCount++;
}
cur = cur->_left;
}
//以blackCount左子树的黑色结点为判断, 判断所有路径下的黑色结点个数
int k = 0;
return _isRBTree(root, k, blackCount);
}
bool _isRBTree(pNode& root, int k, int blackCount) {
//判断是否到一条路径下结尾
if (root == nullptr) {
if (k != blackCount) {
cout << "每条路径下黑色结点个数不相同!" << endl;
return false;
}
return true;
}
//判断是否存在红红情况
if (root->_color == BLACK) {
++k;
}
pNode parent = root->_parent;
if (root->_color == RED && parent->_color == RED) {
cout << "有连续红色的结点" << endl;
return false;
}
return _isRBTree(root->_left, k, blackCount) &&
_isRBTree(root->_right, k, blackCount);
}
private:
void _InOrder(const pNode& root) {
if (root) {
_InOrder(root->_left);
cout << '<' << root->_value.first << "-->" << root->_value.second << '>' << endl;
_InOrder(root->_right);
}
}
private:
pNode _header;
};
//Map类
template<class K, class V>
class Map {
//实现一个内部类
struct MapKeyOfValue {
const K& operator()(const pair<K, V>& data) {
return data.first;
}
};
public:
//重新定义下RBtree类中iterator, 由于是泛型, 因此这块需要添加typename设置为类型
typedef typename RBTree<K, pair<K, V>, MapKeyOfValue>::iterator iterator;
iterator begin() {
return _rb.begin();
}
iterator end() {
return _rb.end();
}
iterator cbegin() {
return _rb.cbegin();
}
iterator cend() {
return _rb.cend();
}
V& operator[](const K& key){
//return ((*(_rb.insert(make_pair(key, V())).first)).second);
//分解操作
pair<iterator, bool> ret = _rb.insert(make_pair(key, V()));
iterator it = ret.first;
return (*it).second;
}
//MAP insert接口
pair<iterator, bool> insert(const pair<K, V>& data) {
return _rb.insert(data);
}
//MAP test遍历
void traverse() {
_rb.InOrder();
}
private:
RBTree<K, pair<K, V>, MapKeyOfValue> _rb;
};
//Set类
template<class K>
class Set {
//定义仿函数
struct SetKeyOfValue {
const K& operator() (const K& data) {
return data;
}
};
public:
typedef typename RBTree<K, K, SetKeyOfValue>::iterator iterator;
iterator begin() {
return _rb.begin();
}
iterator end() {
return _rb.end();
}
iterator cbegin() {
return _rb.cbegin();
}
iterator cend() {
return _rb.cend();
}
//Set插入接口
pair<iterator, bool> insert(const K& data) {
return _rb.insert(data);
}
private:
RBTree<K, K, SetKeyOfValue> _rb;
};
int main() {
Map<int, int> mp;
Set<int> st;
mp.insert(make_pair(4, 1));
mp.insert(make_pair(5, 1));
mp.insert(make_pair(6, 1));
mp.insert(make_pair(7, 1));
mp.insert(make_pair(1, 1));
mp.insert(make_pair(2, 1));
mp.insert(make_pair(3, 1));
st.insert(10);
st.insert(1);
st.insert(9);
st.insert(7);
st.insert(4);
st.insert(5);
cout << "----测试set阶段----" << endl;
for (auto it : st) {
cout << it << " ";
}
cout << endl;
cout << endl;
cout << "----测试map阶段---" << endl;
for (auto it : mp) {
cout << it.first << "--->" << it.second << endl;
}
cout << endl;
cout << "test[] mp[7] = 77, mp[14] = 14" << endl;
cout << endl;
mp[7] = 77;
mp[14] = 14;
for (auto it : mp) {
cout << it.first << "--->" << it.second << endl;
}
return 0;
}
这是本人插入顺序:
set: (10); (1); (9); (7); (4); (5);
map: (4,1);(5,1);(6,1);(7,1);(1,1);(2,1);(3,1);
结果图:
有兴趣的朋友的可以跑一下这个代码, 研究下。