文章目录
一、STL - map 和 set
阅读STL源码就可以发现,其实 set 和 map 自己没有实现啥东西,整体就是对红黑树进行了一个封装,set 和 map 的 insert / erase 接口底层就是调用红黑树的 insert / erase 接口,并且 set 和 map 的迭代器也都是取的红黑树里面的迭代器
那 set 和 map 的核心区别在哪里呢?
set 底层封装了一颗红黑树,是 KV 结构,值得注意的是 key_type 和 value_type 都是 key,说明传了两个 key 给红黑树。
// stl_set.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
typedef Key key_type;
typedef Key value_type; // set的value
//......
private:
typedef rb_tree<key_type, value_type,
identity<value_type>, key_compare, Alloc> rep_type; // 红黑树类型
rep_type t; // red-black tree representing set
//......
};
map 底层封装了一颗红黑树,是 KV 结构,但 key_type 是 key,value_type 是 pair<const Key, T>,说明传了一个 key 和一个键值对(pair)给红黑树。
但这里和我自己理解的有些不一样,不应该只传一个 pair 就行了吗?为啥还要多传一个 key 呢?因为实现查找接口(find)时需要 key 作为形参。
// stl_map.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
typedef Key key_type;
typedef pair<const Key, T> value_type; // map的value
//......
private:
typedef rb_tree<key_type, value_type,
select1st<value_type>, key_compare, Alloc> rep_type; // 红黑树类型
rep_type t; // red-black tree representing map
//......
};
我们发现 stl_map.h 和 stl_set.h 中并没有包含红黑树,那怎么用红黑树的呢?
在库文件
// map
#include <stl_tree.h>
#include <stl_map.h>
#include <stl_multimap.h>
// set
#include <stl_tree.h>
#include <stl_set.h>
#include <stl_multiset.h>
STL源码中红黑树的实现,只截取了关键部分:
红黑树节点结构是一个泛型设计,根据传进来 value 的类型决定是 set 还是 map
// 红黑树节点结构
// value: 节点数据的类型,key或者pair
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 rb_tree_node* link_type;
//......
protected:
link_type header;
//......
};
图解:
二、模拟实现 map 和 set
2.1 改造红黑树的结构
这里直接拿我们自己写的红黑树代码(原先是KV模型的)改造下,使其既可兼容K模型,也可兼容KV模型:
我的红黑树里面具体存的是什么类型的元素,是由模板参数 T 来决定:
- 如果 T 是 Key 那么就是 set
- 如果 T 是 pair<const Key, V> 那么就是 map
1、定义红黑树的节点结构
// 定义红黑颜色
enum Colour
{
BLACK = 0,
RED
};
// 定义红黑树节点结构
// T: 数据的类型,如果是map,则为pair<const K, V>; 如果是set,则为K
template<class T>
struct RBTreeNode
{
T _data; // 数据域
Colour _col; // 用来标记节点颜色
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
RBTreeNode(const T& data) // 构造函数
: _data(data), _col(RED)
, _left(nullptr), _right(nullptr), _parent(nullptr)
{
}
};
2、定义红黑树结构
改造前:
// 定义红黑树结构(KV)
// K: 键值key的类型
// T: 数据的类型,如果是map,则为pair<const K, V>; 如果是set,则为K
template<class K, class T>
class RBTree
{
typedef RBTreeNode<T> Node; // 红黑树节点
private:
Node* _root;
public:
RBTree() :_root(nullptr) {
} // 构造函数
// ......
bool Insert(const T& data); // 插入节点
// ......
};
【思