STL

https://github.com/huihut/interview/blob/master/STL/STL.md

https://github.com/huihut/interview/tree/master/STL

STL 组成

  • 容器(containers)
  • 算法(algorithms)
  • 迭代器(iterators)
  • 仿函数(functors)
  • 配接器(adapters)
  • 空间配置器(allocator)

STL 容器

总体分类:

  • 序列式容器(sequence containers):元素都是可以排序的,但不一定是排序好的
  • 关联式容器(associattive containers)

顺序容器

顺序容器实现能按顺序访问的数据结构。

  • array(C++11):静态的连续数组 (类模板)

  • vector:动态的连续数组 (类模板)

  • deque:双端队列 (类模板)

  • forward_list(C++11 起):单链表 (类模板)

  • list:双链表 (类模板)

关联容器

关联容器实现能快速查找( O(log n) 复杂度)的数据结构。

  • set:唯一键的集合,按照键排序 (类模板)

  • map:键值对的集合,按照键排序,键是唯一的 (类模板)

  • multiset:键的集合,按照键排序 (类模板)

  • multimap:键值对的集合,按照键排序 (类模板)

无序关联容器

无序关联容器提供能快速查找的无序数据结构(哈希表实现的数据结构)。(均摊 O(1) ,最坏情况 O(n) 的复杂度)

  • unordered_set(C++11 起):唯一键的集合,按照键生成散列 (类模板)

  • unordered_map(C++11 起):键值对的集合,按照键生成散列,键是唯一的 (类模板)

  • unordered_multiset(C++11 起):键的集合,按照键生成散列 (类模板)

  • unordered_multimap(C++11 起):键值对的集合,按照键生成散列 (类模板)

容器适配器

容器适配器提供顺序容器的不同接口。

  • stack:适配一个容器以提供栈(LIFO 数据结构)(类模板)

  • queue:适配一个容器以提供队列(FIFO 数据结构)(类模板)

  • priority_queue:适配一个容器以提供优先级队列 (类模板)

span

span 是相接的对象序列上的非占有视图,某个其他对象占有序列的存储。

  • span(C++20):对象的连续序列上的无所有权视图 (类模板)

STL 示例

std::array

//此容器是一个聚合类型,能作为聚合类型聚合初始化
#include <iostream>
#include <array>
#include <string>

int main(){
    //初始化
    std::array<int, 3> a1 = {1, 2, 3};
    std::array<std::string, 2> a2 = {std::string("a"), "b"};
    std::array<int, 3> a3;
    //获取迭代器
    std::array<int, 3>::iterator begin = a1.begin();
    auto cbegin = a1.cbegin();
    auto end = a1.end();
    auto cend = a1.cend();
    auto rbegin = a1.rbegin();
    auto crbegin = a1.crbegin();
    auto rend = a1.rend();
    auto crend = a1.crend();
    //容量
    bool isEmpty = a1.empty();
    int size = a1.size();
    int max_size = a1.max_size();
    //操作
    a3.fill(6);//将定值 value 赋给容器中的所有元素
    a1.swap(a3);//将容器a1内容和a3交换。不导致迭代器和引用关联到别的容器。
    //访问
    int a = a1.front();
    int b = a1.back();
    int c = a1[0];
    int d = a1.at(1);
    int e = std::get<2>(a1);//访问位置的范围有效性在编译时强制,与 at() 或 operator[] 相反
}

std::vector

//此容器是一个聚合类型,能作为聚合类型聚合初始化
#include <iostream>
#include <vector>

int main(){
    //初始化
    std::vector<int> a1(4, 0);
    std::vector<int> a2;
    std::vector<int> a3(a1.begin(), a1.end());
    std::vector<int> a4(a1);
    int tmp[] = {0, 1, 2, 3};
    std::vector<int> a5(tmp, tmp+sizeof(tmp)/sizeof(int));
    std::vector<int> a6 = a1;
    //访问
    int b1 = a1[0];
    int b2 = a1.at(0);
    int b3 = a1.front();
    int b4 = a1.back();
    int b5 = *a1.data();//返回指向内存中数组第一个元素的指针
    //获取迭代器
    std::vector<int>::iterator begin = a1.begin();
    auto cbegin = a1.cbegin();
    auto end = a1.end();
    auto cend = a1.cend();
    auto rbegin = a1.rbegin();
    auto crbegin = a1.crbegin();
    auto rend = a1.rend();
    auto crend = a1.crend();
    //容量
    bool isEmpty = a1.empty();
    int size = a1.size();//返回容纳的元素数
    int capacity = a1.capacity();//返回当前存储空间能够容纳的元素数
    int max_size = a1.max_size();
    int new_cap = size * 2;
    a1.reserve(new_cap);//增加 vector 的容量到大于或等于 new_cap 的值
    a1.shrink_to_fit();//请求移除未使用的容量
    //修改器
    a1.insert(a1.begin(), 10);//在指定位置前插入
    a1.insert(a1.end(), 3, 6);//插入3个6
    a1.emplace(a1.begin(), 11);//可避免不必要的临时对象产生
    a1.erase(a1.begin());
    a1.erase(a1.begin(), a1.begin()+2);
    a1.push_back(12);
    a1.emplace_back(13);
    a1.pop_back();
    a1.resize(32);
    a1.resize(20, 20);
    a1.swap(a2);
    std::swap(a1, a2);
    a1.clear();
}

STL 索引

比较

容器底层数据结构时间复杂度有无序可不可重复其他
array数组随机读改 O(1)无序可重复支持随机访问
vector数组随机读改、尾部插入、尾部删除 O(1) 头部插入、头部删除 O(n)无序可重复支持随机访问
deque双端队列头尾插入、头尾删除 O(1)无序可重复一个中央控制器 + 多个缓冲区,支持首尾快速增删,支持随机访问
forward_list单向链表插入、删除 O(1)无序可重复不支持随机访问
list双向链表插入、删除 O(1)无序可重复不支持随机访问
stackdeque / list顶部插入、顶部删除 O(1)无序可重复deque 或 list 封闭头端开口,不用 vector 的原因应该是容量大小有限制,扩容耗时
queuedeque / list尾部插入、头部删除 O(1)无序可重复deque 或 list 封闭头端开口,不用 vector 的原因应该是容量大小有限制,扩容耗时
priority_queuevector + max-heap插入、删除 O(log2n)有序可重复vector容器+heap处理规则
set红黑树插入、删除、查找 O(log2n)有序不可重复
multiset红黑树插入、删除、查找 O(log2n)有序可重复
map红黑树插入、删除、查找 O(log2n)有序不可重复
multimap红黑树插入、删除、查找 O(log2n)有序可重复
unordered_set哈希表插入、删除、查找 O(1) 最差 O(n)无序不可重复
unordered_multiset哈希表插入、删除、查找 O(1) 最差 O(n)无序可重复
unordered_map哈希表插入、删除、查找 O(1) 最差 O(n)无序不可重复
unordered_multimap哈希表插入、删除、查找 O(1) 最差 O(n)无序可重复

array

array是固定大小的顺序容器,它们保存了一个以严格的线性顺序排列的特定数量的元素。

在内部,一个数组除了它所包含的元素(甚至不是它的大小,它是一个模板参数,在编译时是固定的)以外不保存任何数据。存储大小与用语言括号语法([])声明的普通数组一样高效。这个类只是增加了一层成员函数和全局函数,所以数组可以作为标准容器使用。

与其他标准容器不同,数组具有固定的大小,并且不通过分配器管理其元素的分配:它们是封装固定大小数组元素的聚合类型。因此,他们不能动态地扩大或缩小。

零大小的数组是有效的,但是它们不应该被解除引用(成员的前面,后面和数据)。

与标准库中的其他容器不同,交换两个数组容器是一种线性操作,它涉及单独交换范围内的所有元素,这通常是相当低效的操作。另一方面,这允许迭代器在两个容器中的元素保持其原始容器关联。

数组容器的另一个独特特性是它们可以被当作元组对象来处理:array头部重载get函数来访问数组元素,就像它是一个元组,以及专门的tuple_size和tuple_element类型。

template < class T, size_t N > class array;
方法含义
begin返回指向数组容器中第一个元素的迭代器
end返回指向数组容器中最后一个元素之后的理论元素的迭代器
rbegin返回指向数组容器中最后一个元素的反向迭代器
rend返回一个反向迭代器,指向数组中第一个元素之前的理论元素
cbegin返回指向数组容器中第一个元素的常量迭代器(const_iterator)
cend返回指向数组容器中最后一个元素之后的理论元素的常量迭代器(const_iterator)
crbegin返回指向数组容器中最后一个元素的常量反向迭代器(const_reverse_iterator)
crend返回指向数组中第一个元素之前的理论元素的常量反向迭代器(const_reverse_iterator)
size返回数组容器中元素的数量
max_size返回数组容器可容纳的最大元素数
empty返回一个布尔值,指示数组容器是否为空
operator[]返回容器中第 n(参数)个位置的元素的引用
at返回容器中第 n(参数)个位置的元素的引用
front返回对容器中第一个元素的引用
back返回对容器中最后一个元素的引用
data返回指向容器中第一个元素的指针
fill用 val(参数)填充数组所有元素
swap通过 x(参数)的内容交换数组的内容
get(array)形如 std::get<0>(myarray);传入一个数组容器,返回指定位置元素的引用
relational operators (array)形如 arrayA > arrayB;依此比较数组每个元素的大小关系

vector

vector 是表示可以改变大小的数组的序列容器。

就像数组一样,vector为它们的元素使用连续的存储位置,这意味着它们的元素也可以使用到其元素的常规指针上的偏移来访问,而且和数组一样高效。但是与数组不同的是,它们的大小可以动态地改变,它们的存储由容器自动处理。

在内部,vector使用一个动态分配的数组来存储它们的元素。这个数组可能需要重新分配,以便在插入新元素时增加大小,这意味着分配一个新数组并将所有元素移动到其中。就处理时间而言,这是一个相对昂贵的任务,因此每次将元素添加到容器时矢量都不会重新分配。

相反,vector容器可以分配一些额外的存储以适应可能的增长,并且因此容器可以具有比严格需要包含其元素(即,其大小)的存储更大的实际容量。库可以实现不同的策略的增长到内存使用和重新分配之间的平衡,但在任何情况下,再分配应仅在对数生长的间隔发生尺寸,使得在所述载体的末端各个元件的插入可以与提供分期常量时间复杂性。

因此,与数组相比,载体消耗更多的内存来交换管理存储和以有效方式动态增长的能力。

与其他动态序列容器(deques,lists和 forward_lists )相比,vector非常有效地访问其元素(就像数组一样),并相对有效地从元素末尾添加或移除元素。对于涉及插入或移除除了结尾之外的位置的元素的操作,它们执行比其他位置更差的操作,并且具有比列表和 forward_lists 更不一致的迭代器和引用。

针对 vector 的各种常见操作的复杂度(效率)如下:

  • 随机访问 - 常数 O(1)
  • 在尾部增删元素 - 平摊(amortized)常数 O(1)}}
  • 增删元素 - 至 vector 尾部的线性距离 O(n)}}
template < class T, class Alloc = allocator<T> > class vector;
方法含义
vector构造函数
~vector析构函数,销毁容器对象
operator=将新内容分配给容器,替换其当前内容,并相应地修改其大小
begin返回指向容器中第一个元素的迭代器
end返回指向容器中最后一个元素之后的理论元素的迭代器
rbegin返回指向容器中最后一个元素的反向迭代器
rend返回一个反向迭代器,指向中第一个元素之前的理论元素
cbegin返回指向容器中第一个元素的常量迭代器(const_iterator)
cend返回指向容器中最后一个元素之后的理论元素的常量迭代器(const_iterator)
crbegin返回指向容器中最后一个元素的常量反向迭代器(const_reverse_iterator)
crend返回指向容器中第一个元素之前的理论元素的常量反向迭代器(const_reverse_iterator)
size返回容器中元素的数量
max_size返回容器可容纳的最大元素数
resize调整容器的大小,使其包含 n(参数)个元素
capacity返回当前为 vector 分配的存储空间(容量)的大小
empty返回 vector 是否为空
reserve请求 vector 容量至少足以包含 n(参数)个元素
shrink_to_fit要求容器减小其 capacity(容量)以适应其 size(元素数量)
operator[]返回容器中第 n(参数)个位置的元素的引用
at返回容器中第 n(参数)个位置的元素的引用
front返回对容器中第一个元素的引用
back返回对容器中最后一个元素的引用
data返回指向容器中第一个元素的指针
assign将新内容分配给 vector,替换其当前内容,并相应地修改其 size
push_back在容器的最后一个元素之后添加一个新元素
pop_back删除容器中的最后一个元素,有效地将容器 size 减少一个
insert通过在指定位置的元素之前插入新元素来扩展该容器,通过插入元素的数量有效地增加容器大小
erase从 vector 中删除单个元素(position)或一系列元素([first,last)),这有效地减少了被去除的元素的数量,从而破坏了容器的大小
swap通过 x(参数)的内容交换容器的内容,x 是另一个类型相同、size 可能不同的 vector 对象
clear从 vector 中删除所有的元素(被销毁),留下 size 为 0 的容器
emplace通过在 position(参数)位置处插入新元素 args(参数)来扩展容器
emplace_back在 vector 的末尾插入一个新的元素,紧跟在当前的最后一个元素之后
get_allocator返回与vector关联的构造器对象的副本
swap(vector)容器 x(参数)的内容与容器 y(参数)的内容交换。两个容器对象都必须是相同的类型(相同的模板参数),尽管大小可能不同
relational operators (vector)形如 vectorA > vectorB;依此比较每个元素的大小关系

deque

deque(['dek])(双端队列)是double-ended queue 的一个不规则缩写。deque是具有动态大小的序列容器,可以在两端(前端或后端)扩展或收缩。

特定的库可以以不同的方式实现deques,通常作为某种形式的动态数组。但是在任何情况下,它们都允许通过随机访问迭代器直接访问各个元素,通过根据需要扩展和收缩容器来自动处理存储。

因此,它们提供了类似于vector的功能,但是在序列的开始部分也可以高效地插入和删除元素,而不仅仅是在结尾。但是,与vector不同,deques并不保证将其所有元素存储在连续的存储位置:deque通过偏移指向另一个元素的指针访问元素会导致未定义的行为。

两个vector和deques提供了一个非常相似的接口,可以用于类似的目的,但内部工作方式完全不同:虽然vector使用单个数组需要偶尔重新分配以增长,但是deque的元素可以分散在不同的块的容器,容器在内部保存必要的信息以提供对其任何元素的持续时间和统一的顺序接口(通过迭代器)的直接访问。因此,deques在内部比vector更复杂一点,但是这使得他们在某些情况下更有效地增长,尤其是在重新分配变得更加昂贵的很长序列的情况下。

对于频繁插入或删除开始或结束位置以外的元素的操作,deques表现得更差,并且与列表和转发列表相比,迭代器和引用的一致性更低。

deque上常见操作的复杂性(效率)如下:

  • 随机访问 - 常数O(1)
  • 在结尾或开头插入或移除元素 - 摊销不变O(1)
  • 插入或移除元素 - 线性O(n)
template < class T, class Alloc = allocator<T> > class deque;

deque的方法和vector一样,但其压入弹出操作是双向的:

方法含义
push_back在当前的最后一个元素之后 ,在 deque 容器的末尾添加一个新元素
push_front在 deque 容器的开始位置插入一个新的元素,位于当前的第一个元素之前
pop_back删除 deque 容器中的最后一个元素,有效地将容器大小减少一个
pop_front删除 deque 容器中的第一个元素,有效地减小其大小
emplace_front在 deque 的开头插入一个新的元素,就在其当前的第一个元素之前
emplace_back在 deque 的末尾插入一个新的元素,紧跟在当前的最后一个元素之后

forward_list

forward_list(单向链表)是序列容器,允许在序列中的任何地方进行恒定的时间插入和擦除操作。

forward_list(单向链表)被实现为单链表; 单链表可以将它们包含的每个元素存储在不同和不相关的存储位置中。通过关联到序列中下一个元素的链接的每个元素来保留排序。forward_list容器和列表

之间的主要设计区别容器是第一个内部只保留一个到下一个元素的链接,而后者每个元素保留两个链接:一个指向下一个元素,一个指向前一个元素,允许在两个方向上有效的迭代,但是每个元素消耗额外的存储空间并且插入和移除元件的时间开销略高。因此,forward_list对象比列表对象更有效率,尽管它们只能向前迭代。

与其他基本的标准序列容器(array,vector和deque),forward_list通常在插入,提取和移动容器内任何位置的元素方面效果更好,因此也适用于密集使用这些元素的算法,如排序算法。

的主要缺点修饰符Modifiers S和列表相比这些其它序列容器s是说,他们缺乏可以通过位置的元素的直接访问; 例如,要访问forward_list中的第六个元素,必须从开始位置迭代到该位置,这需要在这些位置之间的线性时间。它们还消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是大型小元素列表的重要因素)。

该修饰符Modifiersclass模板的设计考虑到效率:按照设计,它与简单的手写C型单链表一样高效,实际上是唯一的标准容器,为了效率的考虑故意缺少尺寸成员函数:由于其性质作为一个链表,具有一个需要一定时间的大小的成员将需要它保持一个内部计数器的大小(如列表所示)。这会消耗一些额外的存储空间,并使插入和删除操作效率稍低。要获取forward_list对象的大小,可以使用距离算法的开始和结束,这是一个需要线性时间的操作。

不支持随机访问,仅支持单向访问

方法含义
front访问第一个元素(公开成员函数)
before_begin(cbefore_begin)返回指向第一个元素之前迭代器(公开成员函数)
begin(cbegin)返回指向起始的迭代器(公开成员函数)
end(cend)返回指向末尾的迭代器(公开成员函数)
empty检查容器是否为空(公开成员函数)
max_size返回可容纳的最大元素数(公开成员函数)
clear清除内容(公开成员函数)
insert_after在某个元素后插入新元素(公开成员函数)
emplace_after在元素后原位构造元素(公开成员函数)
erase_after擦除元素后的元素(公开成员函数)
push_front插入元素到容器起始(公开成员函数)
emplace_front在容器头部就地构造元素(公开成员函数)
pop_front移除首元素(公开成员函数)
resize改变容器中可存储元素的个数(公开成员函数)
swap交换内容(公开成员函数)
merge合并二个已排序列表(公开成员函数)
splice_after从另一 forward_list 移动元素(公开成员函数)
remove(remove_if)移除满足特定标准的元素(公开成员函数)
reverse将该链表的所有元素的顺序反转(公开成员函数)
unique删除连续的重复元素(公开成员函数)
sort对元素进行排序(公开成员函数)

list

list,双向链表,是序列容器,允许在序列中的任何地方进行常数时间插入和擦除操作,并在两个方向上进行迭代。

不支持随机访问,支持双向访问

支持双向压入弹出

set

set 是按照特定顺序存储唯一元素的容器。

multiset

map

map 是关联容器,按照特定顺序存储由 key value (键值) 和 mapped value (映射值) 组合形成的元素。

在映射中,键值通常用于对元素进行排序和唯一标识,而映射的值存储与此键关联的内容。该类型的键和映射的值可能不同,并且在部件类型被分组在一起VALUE_TYPE,这是一种对类型结合两种:

typedef pair<const Key, T> value_type;

在内部,映射中的元素总是按照由其内部比较对象(比较类型)指示的特定的严格弱排序标准按键排序。映射容器通常比unordered_map容器慢,以通过它们的键来访问各个元素,但是它们允许基于它们的顺序对子集进行直接迭代。 在该映射值地图可以直接通过使用其相应的键来访问括号运算符((操作符[] )。 映射通常如实施

template < class Key,                                     // map::key_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;
方法含义
map构造函数
begin返回引用容器中第一个元素的迭代器
key_comp返回容器用于比较键的比较对象的副本
value_comp返回可用于比较两个元素的比较对象,以获取第一个元素的键是否在第二个元素之前
find在容器中搜索具有等于 k(参数)的键的元素,如果找到则返回一个迭代器,否则返回 map::end 的迭代器
count在容器中搜索具有等于 k(参数)的键的元素,并返回匹配的数量
lower_bound返回一个非递减序列 [first, last)(参数)中的第一个大于等于值 val(参数)的位置的迭代器
upper_bound返回一个非递减序列 [first, last)(参数)中第一个大于 val(参数)的位置的迭代器
equal_range获取相同元素的范围,返回包含容器中所有具有与 k(参数)等价的键的元素的范围边界(pair< map<char,int>::iterator, map<char,int>::iterator >

multimap

unordered_set

unordered_multiset

unordered_map

unordered_multimap

stack

stack 是一种容器适配器,用于在LIFO(后进先出)的操作,其中元素仅从容器的一端插入和提取。

queue

queue 是一种容器适配器,用于在FIFO(先入先出)的操作,其中元素插入到容器的一端并从另一端提取。

priority_queue

STL 算法

算法底层算法时间复杂度可不可重复
find顺序查找O(n)可重复
sort内省排序O(n*log2n)可重复
// 简单查找算法,要求输入迭代器(input iterator)
find(beg, end, val); // 返回一个迭代器,指向输入序列中第一个等于 val 的元素,未找到返回 end
find_if(beg, end, unaryPred); // 返回一个迭代器,指向第一个满足 unaryPred 的元素,未找到返回 end
find_if_not(beg, end, unaryPred); // 返回一个迭代器,指向第一个令 unaryPred 为 false 的元素,未找到返回 end
count(beg, end, val); // 返回一个计数器,指出 val 出现了多少次
count_if(beg, end, unaryPred); // 统计有多少个元素满足 unaryPred
all_of(beg, end, unaryPred); // 返回一个 bool 值,判断是否所有元素都满足 unaryPred
any_of(beg, end, unaryPred); // 返回一个 bool 值,判断是否任意(存在)一个元素满足 unaryPred
none_of(beg, end, unaryPred); // 返回一个 bool 值,判断是否所有元素都不满足 unaryPred

// 查找重复值的算法,传入向前迭代器(forward iterator)
adjacent_find(beg, end); // 返回指向第一对相邻重复元素的迭代器,无相邻元素则返回 end
adjacent_find(beg, end, binaryPred); // 返回指向第一对相邻重复元素的迭代器,无相邻元素则返回 end
search_n(beg, end, count, val); // 返回一个迭代器,从此位置开始有 count 个相等元素,不存在则返回 end
search_n(beg, end, count, val, binaryPred); // 返回一个迭代器,从此位置开始有 count 个相等元素,不存在则返回 end

// 查找子序列算法,除 find_first_of(前两个输入迭代器,后两个前向迭代器) 外,都要求两个前向迭代器
search(beg1, end1, beg2, end2); // 返回第二个输入范围(子序列)在爹一个输入范围中第一次出现的位置,未找到则返回 end1
search(beg1, end1, beg2, end2, binaryPred); // 返回第二个输入范围(子序列)在爹一个输入范围中第一次出现的位置,未找到则返回 end1
find_first_of(beg1, end1, beg2, end2); // 返回一个迭代器,指向第二个输入范围中任意元素在第一个范围中首次出现的位置,未找到则返回end1
find_first_of(beg1, end1, beg2, end2, binaryPred); // 返回一个迭代器,指向第二个输入范围中任意元素在第一个范围中首次出现的位置,未找到则返回end1
find_end(beg1, end1, beg2, end2); // 类似 search,但返回的最后一次出现的位置。如果第二个输入范围为空,或者在第一个输入范围为空,或者在第一个输入范围中未找到它,则返回 end1
find_end(beg1, end1, beg2, end2, binaryPred); // 类似 search,但返回的最后一次出现的位置。如果第二个输入范围为空,或者在第一个输入范围为空,或者在第一个输入范围中未找到它,则返回 end1

// 其他只读算法,传入输入迭代器
for_each(beg, end, unaryOp); // 对输入序列中的每个元素应用可调用对象 unaryOp,unaryOp 的返回值被忽略
mismatch(beg1, end1, beg2); // 比较两个序列中的元素。返回一个迭代器的 pair,表示两个序列中第一个不匹配的元素
mismatch(beg1, end1, beg2, binaryPred); // 比较两个序列中的元素。返回一个迭代器的 pair,表示两个序列中第一个不匹配的元素
equal(beg1, end1, beg2); // 比较每个元素,确定两个序列是否相等。
equal(beg1, end1, beg2, binaryPred); // 比较每个元素,确定两个序列是否相等。

// 二分搜索算法,传入前向迭代器或随机访问迭代器(random-access iterator),要求序列中的元素已经是有序的。通过小于运算符(<)或 comp 比较操作实现比较。
lower_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end
lower_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end
upper_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end
upper_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end
equal_range(beg, end, val); // 返回一个 pair,其 first 成员是 lower_bound 返回的迭代器,其 second 成员是 upper_bound 返回的迭代器
binary_search(beg, end, val); // 返回一个 bool 值,指出序列中是否包含等于 val 的元素。对于两个值 x 和 y,当 x 不小于 y 且 y 也不小于 x 时,认为它们相等。

// 只写不读算法,要求输出迭代器(output iterator)
fill(beg, end, val); // 将 val 赋予每个元素,返回 void
fill_n(beg, cnt, val); // 将 val 赋予 cnt 个元素,返回指向写入到输出序列最有一个元素之后位置的迭代器
genetate(beg, end, Gen); // 每次调用 Gen() 生成不同的值赋予每个序列,返回 void
genetate_n(beg, cnt, Gen); // 每次调用 Gen() 生成不同的值赋予 cnt 个序列,返回指向写入到输出序列最有一个元素之后位置的迭代器

// 使用输入迭代器的写算法,读取一个输入序列,将值写入到一个输出序列(dest)中
copy(beg, end, dest); // 从输入范围将元素拷贝所有元素到 dest 指定定的目的序列
copy_if(beg, end, dest, unaryPred); // 从输入范围将元素拷贝满足 unaryPred 的元素到 dest 指定定的目的序列
copy_n(beg, n, dest); // 从输入范围将元素拷贝前 n 个元素到 dest 指定定的目的序列
move(beg, end, dest); // 对输入序列中的每个元素调用 std::move,将其移动到迭代器 dest 开始始的序列中
transform(beg, end, dest, unaryOp); // 调用给定操作(一元操作),并将结果写到dest中
transform(beg, end, beg2, dest, binaryOp); // 调用给定操作(二元操作),并将结果写到dest中
replace_copy(beg, end, dest, old_val, new_val); // 将每个元素拷贝到 dest,将等于 old_val 的的元素替换为 new_val
replace_copy_if(beg, end, dest, unaryPred, new_val); // 将每个元素拷贝到 dest,将满足 unaryPred 的的元素替换为 new_val
merge(beg1, end1, beg2, end2, dest); // 两个输入序列必须都是有序的,用 < 运算符将合并后的序列写入到 dest 中
merge(beg1, end1, beg2, end2, dest, comp); // 两个输入序列必须都是有序的,使用给定的比较操作(comp)将合并后的序列写入到 dest 中

// 使用前向迭代器的写算法,要求前向迭代器
iter_swap(iter1, iter2); // 交换 iter1 和 iter2 所表示的元素,返回 void
swap_ranges(beg1, end1, beg2); // 将输入范围中所有元素与 beg2 开始的第二个序列中所有元素进行交换。返回递增后的的 beg2,指向最后一个交换元素之后的位置。
replace(beg, end, old_val, new_val); // 用 new_val 替换等于 old_val 的每个匹配元素
replace_if(beg, end, unaryPred, new_val); // 用 new_val 替换满足 unaryPred 的每个匹配元素

// 使用双向迭代器的写算法,要求双向选代器(bidirectional iterator)
copy_backward(beg, end, dest); // 从输入范围中拷贝元素到指定目的位置。如果范围为空,则返回值为 dest;否则,返回值表示从 *beg 中拷贝或移动的元素。
move_backward(beg, end, dest);  // 从输入范围中移动元素到指定目的位置。如果范围为空,则返回值为 dest;否则,返回值表示从 *beg 中拷贝或移动的元素。
inplace_merge(beg, mid, end); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用 < 比较元素。
inplace_merge(beg, mid, end, comp); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用给定的 comp 操作。

// 划分算法,要求双向选代器(bidirectional iterator)
is_partitioned(beg, end, unaryPred); // 如果所有满足谓词 unaryPred 的元素都在不满足 unarypred 的元素之前,则返回 true。若序列为空,也返回 true
partition_copy(beg, end, dest1, dest2, unaryPred); // 将满足 unaryPred 的元素拷贝到到 dest1,并将不满足 unaryPred 的元素拷贝到到 dest2。返回一个迭代器 pair,其 first 成员表示拷贝到 dest1 的的元素的末尾,second 表示拷贝到 dest2 的元素的末尾。
partitioned_point(beg, end, unaryPred); // 输入序列必须是已经用 unaryPred 划分过的。返回满足  unaryPred 的范围的尾后迭代器。如果返回的迭代器不是 end,则它指向的元素及其后的元素必须都不满足 unaryPred
stable_partition(beg, end, unaryPred); // 使用 unaryPred 划分输入序列。满足 unaryPred 的元素放置在序列开始,不满足的元素放在序列尾部。返回一个迭代器,指向最后一个满足 unaryPred 的元素之后的位置如果所有元素都不满足 unaryPred,则返回 beg
partition(beg, end, unaryPred); // 使用 unaryPred 划分输入序列。满足 unaryPred 的元素放置在序列开始,不满足的元素放在序列尾部。返回一个迭代器,指向最后一个满足 unaryPred 的元素之后的位置如果所有元素都不满足 unaryPred,则返回 beg

// 排序算法,要求随机访问迭代器(random-access iterator)
sort(beg, end); // 排序整个范围
stable_sort(beg, end); // 排序整个范围(稳定排序)
sort(beg, end, comp); // 排序整个范围
stable_sort(beg, end, comp); // 排序整个范围(稳定排序)
is_sorted(beg, end); // 返回一个 bool 值,指出整个输入序列是否有序
is_sorted(beg, end, comp); // 返回一个 bool 值,指出整个输入序列是否有序
is_sorted_until(beg, end); // 在输入序列中査找最长初始有序子序列,并返回子序列的尾后迭代器
is_sorted_until(beg, end, comp); // 在输入序列中査找最长初始有序子序列,并返回子序列的尾后迭代器
partial_sort(beg, mid, end); // 排序 mid-beg 个元素。即,如果 mid-beg 等于 42,则此函数将值最小的 42 个元素有序放在序列前 42 个位置
partial_sort(beg, mid, end, comp); // 排序 mid-beg 个元素。即,如果 mid-beg 等于 42,则此函数将值最小的 42 个元素有序放在序列前 42 个位置
partial_sort_copy(beg, end, destBeg, destEnd); // 排序输入范围中的元素,并将足够多的已排序元素放到 destBeg 和 destEnd 所指示的序列中
partial_sort_copy(beg, end, destBeg, destEnd, comp); // 排序输入范围中的元素,并将足够多的已排序元素放到 destBeg 和 destEnd 所指示的序列中
nth_element(beg, nth, end); // nth 是一个迭代器,指向输入序列中第 n 大的元素。nth 之前的元素都小于等于它,而之后的元素都大于等于它
nth_element(beg, nth, end, comp); // nth 是一个迭代器,指向输入序列中第 n 大的元素。nth 之前的元素都小于等于它,而之后的元素都大于等于它

// 使用前向迭代器的重排算法。普通版本在输入序列自身内部重拍元素,_copy 版本完成重拍后写入到指定目的序列中,而不改变输入序列
remove(beg, end, val); // 通过用保留的元素覆盖要删除的元素实现删除 ==val 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器
remove_if(beg, end, unaryPred); // 通过用保留的元素覆盖要删除的元素实现删除满足 unaryPred 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器
remove_copy(beg, end, dest, val); // 通过用保留的元素覆盖要删除的元素实现删除 ==val 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器
remove_copy_if(beg, end, dest, unaryPred); // 通过用保留的元素覆盖要删除的元素实现删除满足 unaryPred 的元素,返回一个指向最后一个删除元素的尾后位置的迭代器
unique(beg, end); // 通过对覆盖相邻的重复元素(用 == 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置
unique (beg, end, binaryPred); // 通过对覆盖相邻的重复元素(用 binaryPred 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置
unique_copy(beg, end, dest); // 通过对覆盖相邻的重复元素(用 == 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置
unique_copy_if(beg, end, dest, binaryPred); // 通过对覆盖相邻的重复元素(用 binaryPred 确定是否相同)实现重排序列。返回一个迭代器,指向不重复元素的尾后位置
rotate(beg, mid, end); // 围绕 mid 指向的元素进行元素转动。元素 mid 成为为首元素,随后是 mid+1 到到 end 之前的元素,再接着是 beg 到 mid 之前的元素。返回一个迭代器,指向原来在 beg 位置的元素
rotate_copy(beg, mid, end, dest); // 围绕 mid 指向的元素进行元素转动。元素 mid 成为为首元素,随后是 mid+1 到到 end 之前的元素,再接着是 beg 到 mid 之前的元素。返回一个迭代器,指向原来在 beg 位置的元素

// 使用双向迭代器的重排算法
reverse(beg, end); // 翻转序列中的元素,返回 void
reverse_copy(beg, end, dest);; // 翻转序列中的元素,返回一个迭代器,指向拷贝到目的序列的元素的尾后位置

// 使用随机访问迭代器的重排算法
random_shuffle(beg, end); // 混洗输入序列中的元素,返回 void
random_shuffle(beg, end, rand); // 混洗输入序列中的元素,rand 接受一个正整数的随机对象,返回 void
shuffle(beg, end, Uniform_rand); // 混洗输入序列中的元素,Uniform_rand 必须满足均匀分布随机数生成器的要求,返回 void

// 最小值和最大值,使用 < 运算符或给定的比较操作 comp 进行比较
min(val1, va12); // 返回 val1 和 val2 中的最小值,两个实参的类型必须完全一致。参数和返回类型都是 const的引引用,意味着对象不会被拷贝。下略
min(val1, val2, comp);
min(init_list);
min(init_list, comp);
max(val1, val2);
max(val1, val2, comp);
max(init_list);
max(init_list, comp);
minmax(val1, val2); // 返回一个 pair,其 first 成员为提供的值中的较小者,second 成员为较大者。下略
minmax(vall, val2, comp);
minmax(init_list);
minmax(init_list, comp);
min_element(beg, end); // 返回指向输入序列中最小元素的迭代器
min_element(beg, end, comp); // 返回指向输入序列中最小元素的迭代器
max_element(beg, end); // 返回指向输入序列中最大元素的迭代器
max_element(beg, end, comp); // 返回指向输入序列中最大元素的迭代器
minmax_element(beg, end); // 返回一个 pair,其中 first 成员为最小元素,second 成员为最大元素
minmax_element(beg, end, comp); // 返回一个 pair,其中 first 成员为最小元素,second 成员为最大元素

// 字典序比较,根据第一对不相等的元素的相对大小来返回结果。如果第一个序列在字典序中小于第二个序列,则返回 true。否则,返回 fa1se。如果个序列比另一个短,且所有元素都与较长序列的对应元素相等,则较短序列在字典序中更小。如果序列长度相等,且对应元素都相等,则在字典序中任何一个都不大于另外一个。
lexicographical_compare(beg1, end1, beg2, end2);
lexicographical_compare(beg1, end1, beg2, end2, comp);

其它

tuple

元组是一个能够容纳元素集合的对象。每个元素可以是不同的类型。

元组是一个能够容纳元素集合的对象。每个元素可以是不同的类型。

template <class... Types> class tuple;

Example

#include <iostream>     // std::cout
#include <tuple>        // std::tuple, std::get, std::tie, std::ignore

int main ()
{
  std::tuple<int,char> foo (10,'x');
  auto bar = std::make_tuple ("test", 3.1, 14, 'y');

  std::get<2>(bar) = 100;                                    // access element

  int myint; char mychar;

  std::tie (myint, mychar) = foo;                            // unpack elements
  std::tie (std::ignore, std::ignore, myint, mychar) = bar;  // unpack (with ignore)

  mychar = std::get<3>(bar);

  std::get<0>(foo) = std::get<2>(bar);
  std::get<1>(foo) = mychar;

  std::cout << "foo contains: ";
  std::cout << std::get<0>(foo) << ' ';
  std::cout << std::get<1>(foo) << '\n';

  return 0;
}

Output

foo contains: 100 y

tuple::tuple

构建一个 tuple(元组)对象。

这涉及单独构建其元素,初始化取决于调用的构造函数形式:

(1)默认的构造函数

构建一个 元组对象的元素值初始化。

(2)复制/移动构造函数

该对象使用tpl的内容进行初始化 元组目的。tpl 的相应元素被传递给每个元素的构造函数。

(3)隐式转换构造函数

同上。tpl中的 所有类型都可以隐含地转换为构造中它们各自元素的类型元组 目的。

(4)初始化构造函数 用elems中的相应元素初始化每个元素。elems 的相应元素被传递给每个元素的构造函数。

(5)对转换构造函数

该对象有两个对应于pr.first和的元素pr.second。PR中的所有类型都应该隐含地转换为其中各自元素的类型元组 目的。

(6)分配器版本

和上面的版本一样,除了每个元素都是使用allocator alloc构造的。

default (1)	
constexpr tuple();
copy / move (2)	
tuple (const tuple& tpl) = default;
tuple (tuple&& tpl) = default;
implicit conversion (3)	
template <class... UTypes>
  tuple (const tuple<UTypes...>& tpl);
template <class... UTypes>
  tuple (tuple<UTypes...>&& tpl);
initialization (4)	
explicit tuple (const Types&... elems);
template <class... UTypes>
  explicit tuple (UTypes&&... elems);
conversion from pair (5)	
template <class U1, class U2>
  tuple (const pair<U1,U2>& pr);
template <class U1, class U2>
  tuple (pair<U1,U2>&& pr);
allocator (6)	
template<class Alloc>
  tuple (allocator_arg_t aa, const Alloc& alloc);
template<class Alloc>
  tuple (allocator_arg_t aa, const Alloc& alloc, const tuple& tpl);
template<class Alloc>
  tuple (allocator_arg_t aa, const Alloc& alloc, tuple&& tpl);
template<class Alloc,class... UTypes>
  tuple (allocator_arg_t aa, const Alloc& alloc, const tuple<UTypes...>& tpl);
template<class Alloc, class... UTypes>
  tuple (allocator_arg_t aa, const Alloc& alloc, tuple<UTypes...>&& tpl);
template<class Alloc>
  tuple (allocator_arg_t aa, const Alloc& alloc, const Types&... elems);
template<class Alloc, class... UTypes>
  tuple (allocator_arg_t aa, const Alloc& alloc, UTypes&&... elems);
template<class Alloc, class U1, class U2>
  tuple (allocator_arg_t aa, const Alloc& alloc, const pair<U1,U2>& pr);
template<class Alloc, class U1, class U2>
  tuple (allocator_arg_t aa, const Alloc& alloc, pair<U1,U2>&& pr);

Example

#include <iostream>     // std::cout
#include <utility>      // std::make_pair
#include <tuple>        // std::tuple, std::make_tuple, std::get

int main ()
{
  std::tuple<int,char> first;                             // default
  std::tuple<int,char> second (first);                    // copy
  std::tuple<int,char> third (std::make_tuple(20,'b'));   // move
  std::tuple<long,char> fourth (third);                   // implicit conversion
  std::tuple<int,char> fifth (10,'a');                    // initialization
  std::tuple<int,char> sixth (std::make_pair(30,'c'));    // from pair / move

  std::cout << "sixth contains: " << std::get<0>(sixth);
  std::cout << " and " << std::get<1>(sixth) << '\n';

  return 0;
}

Output

sixth contains: 30 and c

pair

这个类把一对值(values)结合在一起,这些值可能是不同的类型(T1 和 T2)。每个值可以被公有的成员变量first、second访问。

pair是tuple(元组)的一个特例。

pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。

应用:

  • 可以将两个类型数据组合成一个如map<key, value>
  • 当某个函数需要两个返回值时
template <class T1, class T2> struct pair;

pair::pair

构建一个pair对象。

这涉及到单独构建它的两个组件对象,初始化依赖于调用的构造器形式:

(1)默认的构造函数

构建一个 对对象的元素值初始化。

(2)复制/移动构造函数(和隐式转换)

该对象被初始化为pr的内容 对目的。pr 的相应成员被传递给每个成员的构造函数。

(3)初始化构造函数

会员 第一是由一个和成员构建的第二与b。

(4)分段构造

构造成员 first 和 second 到位,传递元素first_args 作为参数的构造函数 first,和元素 second_args 到的构造函数 second 。

default (1)	
constexpr pair();
copy / move (2)	
template<class U, class V> pair (const pair<U,V>& pr);
template<class U, class V> pair (pair<U,V>&& pr);
pair (const pair& pr) = default;
pair (pair&& pr) = default;
initialization (3)	
pair (const first_type& a, const second_type& b);
template<class U, class V> pair (U&& a, V&& b);
piecewise (4)	
template <class... Args1, class... Args2>
  pair (piecewise_construct_t pwc, tuple<Args1...> first_args,
                                   tuple<Args2...> second_args);

Example

#include <utility>      // std::pair, std::make_pair
#include <string>       // std::string
#include <iostream>     // std::cout

int main () {
  std::pair <std::string,double> product1;                     // default constructor
  std::pair <std::string,double> product2 ("tomatoes",2.30);   // value init
  std::pair <std::string,double> product3 (product2);          // copy constructor

  product1 = std::make_pair(std::string("lightbulbs"),0.99);   // using make_pair (move)

  product2.first = "shoes";                  // the type of first is string
  product2.second = 39.90;                   // the type of second is double

  std::cout << "The price of " << product1.first << " is $" << product1.second << '\n';
  std::cout << "The price of " << product2.first << " is $" << product2.second << '\n';
  std::cout << "The price of " << product3.first << " is $" << product3.second << '\n';
  return 0;
}

Output

The price of lightbulbs is $0.99
The price of shoes is $39.9
The price of tomatoes is $2.3