前言
最近刷题有用到set, 于是突然来了兴致,就想了解 STL 中set 的实现。说起set,立刻就能想到的有几点,set 底层用红黑树实现,set 是天然有序的,set 可以去重(不包含重复元素,当然 multiset 可以)。然而还是想对 set 的实现做个了解,比如到底是怎么插入删除的?侯捷大佬的 《STL源码剖析》很不错,菜鸡本鸡没有好好看。带着侯捷大佬的名言“源码面前无秘密”,看了一下 set 的源码,做个简单记录。主要关注 set 的插入删除数据,至于红黑树的实现,就不深究了。不同C++版本的实现的也不尽相同,不做一概而论。
源码位置:阅读源码首先需要知道源码位置在哪儿。stl源码一般存放在 include/.../bits/ 文件夹下。
Windows:用编译器直接就可以打开头文件的具体源码,不多说。
Linux:linux底下一般头文件都是存放在 /usr/include 底下,C++源码在 C++文件夹下,找到里面的bits文件夹。比如我的就是/usr/include/c++/5/bits。bits外面是C++的头文件,一般都是只做头文件包含,具体STL实现在bits文件夹下。
/** @file include/set
* This is a Standard C++ Library header.
*/
#ifndef _GLIBCXX_SET
#define _GLIBCXX_SET 1
#pragma GCC system_header
#include <bits/stl_tree.h> // 红黑树实现
#include <bits/stl_set.h> // 主要 set 类定义已经方法实现,以下源码实现都是此文件中
#include <bits/stl_multiset.h> //multiset
#include <bits/range_access.h>
#ifdef _GLIBCXX_DEBUG
# include <debug/set>
#endif
#ifdef _GLIBCXX_PROFILE
# include <profile/set>
#endif
#endif /* _GLIBCXX_SET */
set基本定义
template<typename _Key, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<_Key> >
// 三个模板参数,第一个就是数据类型;第二个比较函数,仿函数,默认是less;
// 第三个是分配器, 默认 std::allocator
class set
{
// concept requirements
typedef typename _Alloc::value_type _Alloc_value_type;
__glibcxx_class_requires(_Key, _SGIAssignableConcept)
__glibcxx_class_requires4(_Compare, bool, _Key, _Key,
_BinaryFunctionConcept)
__glibcxx_class_requires2(_Key, _Alloc_value_type, _SameTypeConcept)
public:
// typedefs:
//@{
/// Public typedefs. typedef 定义一些别名,后面源码中以别名代替
typedef _Key key_type;
typedef _Key value_type;
typedef _Compare key_compare;
typedef _Compare value_compare;
typedef _Alloc allocator_type;
private:
typedef typename _Alloc::template rebind<_Key>::other _Key_alloc_type;
typedef _Rb_tree<key_type, value_type, _Identity<value_type>,
key_compare, _Key_alloc_type> _Rep_type;
_Rep_type _M_t; // Red-black tree representing set. // 红黑树别名
代码过多,只展示部分。一个容器的使用,首先要看容器的定义,然后是容器的使用方法。可知 set 有三个模板参数,第一个数据类型,第二个比较函数,第三个是分配器。比较函数都是放在 stl_function.h 文件中,less,greater 等等都是实现的仿函数,set 默认是 less。一般分配器就用std::allocator,就不自己再指定了,当然分配器也有其他实现,侯捷大佬有讲。
/// One of the @link comparison_functors comparison functors@endlink.
template<typename _Tp> // less 函数为例
struct less : public binary_function<_Tp, _Tp, bool>
{
bool