在现实世界中,许多数据和元素都没有天然的顺序,比如人群、车辆或是数字的集合。我们常常需要一种方法,来将这些本来无序的事物整理成有序的结构,方便我们管理和访问。在 C++ 中,set就是这样一个“有序指挥官”,它能够在无序的世界中,快速为我们建立秩序,确保元素的有序性和高效的操作。
1.set简介
C++ 中的 set
是一种 关联容器,它存储唯一的元素,并保证这些元素按照一定的顺序排列。元素的顺序通常是 升序,但也可以根据自定义的比较函数来进行排序。与 vector
或 list
等容器不同,set
不允许重复的元素,它会自动忽略重复插入的元素。
简而言之,set
是一个自动为我们整理无序数据的工具,它确保数据总是按顺序存储,并且不包含重复项。
1.1 序列式容器和关联性容器
1.2 底层实现:红黑树的指挥棒
set
的有序性和高效性来自于其底层实现——红黑树。红黑树是一种自平衡的二叉查找树,它通过一些规则来保持树的平衡,确保树的高度始终在对数级别,从而保证了查找、插入和删除操作的高效性。
红黑树遵循以下五条规则:
- 节点的颜色:每个节点要么是红色,要么是黑色。
- 根节点是黑色:树的根节点总是黑色的。
- 红色节点的子节点是黑色:如果一个节点是红色的,那么它的子节点必须是黑色的。这意味着红色节点不能连续出现。
- 从任何节点到其所有叶子的简单路径包含相同数目的黑色节点:每条路径上黑色节点的数量必须相同。
- 所有叶子节点是黑色:红黑树的叶子节点(即空节点)是黑色的。
通过这五条规则,红黑树在任何插入和删除操作之后都能够重新平衡自己,保持树的高度不超过 2 * log(n)
,确保 O(log n) 的查找、插入和删除时间复杂度。
红黑树拥有以下特性,使得它成为了 C++ set
的理想选择:
- 自平衡:插入和删除操作会自动调整树的结构,确保树的高度保持在 O(log n) 范围内。
- 有序存储:树中的节点按顺序排列,这保证了元素的快速查找和排序。
- O(log n) 时间复杂度:无论是查找、插入还是删除操作,时间复杂度都是 O(log n),即使在数据量极大的情况下也能保持高效。
2. set的构造函数
empty (1) | explicit set (const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()); |
---|---|
range (2) | template <class InputIterator> set (InputIterator first, InputIterator last, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()); |
copy (3) | set (const set& x); |
2.1 构造函数
在 C++ 中,set
容器提供了几种构造函数,适用于不同的使用场景。以下是你提供的构造函数的详细解析:
1. 默认构造函数:empty()
set<int> first();
这是最简单的构造函数,用于创建一个空的 set
。它初始化一个没有任何元素的集合。此构造函数会使用默认的比较器(key_compare
)和分配器(allocator_type
)。这种构造方式适合在后续添加元素时使用。
2. 范围构造函数:range()
template <class InputIterator>
set(InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
int myints[] = { 10,20,30,40,50 };
std::set<int> second(myints, myints + 5); // range
范围构造函数允许你通过指定一个元素范围来创建 set
。通过提供一对迭代器 [first, last]
,可以将一段容器(如 vector
或数组)的元素拷贝到 set
中。
此构造函数会使用提供的 key_compare
来进行元素的排序,以及使用 allocator_type
来进行内存分配。如果未提供这两个参数,则会使用默认的比较器和分配器
3. 拷贝构造函数:copy()
set(const set& x);
拷贝构造函数会通过复制另一个 set
来创建一个新的 set
。它会复制整个元素集合,并保持相同的排序规则和内存分配方式。当你想要创建一个与另一个 set
内容相同的新 set
时,这个构造函数非常有用。
std::set<int> third(second);
2.2 默认比较器和默认分配器
在 C++ 中,set
容器的默认比较器和分配器分别是:
1. 默认比较器(key_compare
)
set
是一个基于平衡二叉搜索树(通常是红黑树)的容器,元素会根据某种顺序进行排序。默认情况下,set
使用 std::less<T>
作为比较器,T
是 set
存储元素的类型。
std::less<T>
:是一个函数对象(也叫谓词),其作用是如果左侧的元素小于右侧的元素,则返回