STL学习笔记
容器概述
- STL包含许多不同的容器类,分为三个类别:序列容器、关联容器、容器适配器
序列容器
- 序列容器会维护容器中元素的顺序,可以选择元素的插入位置,例如数组。
- 在C++11中,STL包含6个序列容器类:
std::vector、std::deque、std::array、std::list、std::forward_list、std::basic_string
vector
类是一个可以动态增长的数组、允许通过[]运算符随机访问元素、可以在末尾快速地添加或删除元素
#include <vector>
#include <iostream>
int main()
{
std::vector<int> vect;
for (int count=0; count < 6; ++count)
vect.push_back(10 - count); // insert at end of array
for (int index=0; index < vect.size(); ++index)
std::cout << vect[index] << ' ';
std::cout << '\n';
}
// 输出结果为:10 9 8 7 6 5
deque
是一个双端队列类,具体实现是一个可以从两端增长的动态数组
#include <iostream>
#include <deque>
int main()
{
std::deque<int> deq;
for (int count=0; count < 3; ++count)
{
deq.push_back(count); // insert at end of array
deq.push_front(10 - count); // insert at front of array
}
for (int index=0; index < deq.size(); ++index)
std::cout << deq[index] << ' ';
std::cout << '\n';
}
// 输出结果为:8 9 10 0 1 2
list
是一种特殊的序列容器,称为双向链表。容器中的每个元素都包含指向列表中上一个元素和下一个元素的指针- 列表只提供对开头和结尾的访问,不能随机访问。如果想访问中间某个值,必须从某一端开始遍历列表
- 列表的优点是插入元素的速度快
- 尽管STL的string(wstring)通常不作为序列容器的类型,但它们本质上是序列容器,可以认为是char(wchar)数据类型的元素组成的向量
关联容器
- 关联容器在插入元素时会自动排序。默认情况下,关联容器使用运算符<比较元素
set
是存储唯一元素的容器类,不允许有重复的元素,元素会根据值进行排序multiset
是可以存储重复元素的set
map
是一个集合,其中每个元素都是一个键值对。键用于排序和索引数据并且是唯一的,值是实际的数据multimap
也叫字典,允许键重复。(例如字典中的一个单词可以有多个含义)
容器适配器
- 容器适配器是特殊的预定义容器,适用于特殊用途
- 容器适配器可以自由选择所使用的序列容器
stack
是一个FILO(先进后出)的容器,插入元素和移除元素都是在容器的末尾。stack
使用deque
作为默认的序列容器,也可以使用vector
和list
queue
是一个FIFO(先进先出)的容器,插入元素在容器尾部,移除元素在容器头部。queue
默认使用deque
,也可以使用list
priority queue
是一种元素通过运算符<保持排序的队列。插入元素时保持队列是有序的,从头部删除元素时会返回优先级最高的元素
迭代器概述
- 迭代器是一个对象,它可以遍历一个容器类。对于列表类和关联类,迭代器是访问元素的主要方式
- 一个迭代器可以看做是一个指向容器中给定元素的
指针
,它提供了一组重载的操作符以实现定义好的功能:*
:对迭代器的解引用会返回迭代器当前指向的元素++/--
:将迭代器指向下一个/上一个元素==/!=
:判断两个迭代器是否指向同一个元素。如果要判断两个迭代器指向的元素的值是否相等,需要先对迭代器解引用,再使用比较运算符=
:让迭代器指向新的位置(通常是容器的开头或结尾)。如果要为迭代器指向的元素赋值,需要先对迭代器解引用,再使用赋值运算符
- 每个容器类都包含四个基本的成员函数,用于操作符=:
begin()
:返回一个指向容器中第一个元素的迭代器end()
:返回一个指向容器中最后一个元素之后的位置的迭代器cbegin()
:返回一个指向容器中第一个元素的只读迭代器cend()
:返回一个指向容器中最后一个元素之后的位置的只读迭代器
- 所有容器类都至少提供两种迭代器:
container::iterator
和container::const_iterator
#include "iostream"
#include "vector"
int main() {
std::vector<int> vector;
for (int i = 0; i < 6; ++i)
vector.push_back(i);
std::vector<int>::const_iterator iterator = vector.cbegin();
while (iterator != vector.cend()) {
std::cout << *iterator << ' ';
++iterator;
}
return 0;
}
- 迭代器提供了一种简单的方式来遍历容器类的元素,而无需了解容器类的具体实现
- 迭代器必须在每个容器类的基础上实现,因为迭代器无需知道容器类是如何实现的。因此迭代器总是绑定到特定的容器类
算法概述
- STL提供了许多通用算法来处理容器类的元素。例如
search、sort、insert、remove、copy
- 算法被实现为使用迭代器操作的函数。这意味着每个算法只需要实现一次,然后就可以用于所有提供了一组迭代器的容器类(包括自定义的容器类)
虽然这可以帮助快速编写复杂的代码,但是也有缺点:某些算法和容器类的组合可能不起作用、可能导致无限循环、可能性能较差
- 要使用任何STL算法,只需要包含
<algorithm>
这个头文件 - 当一个搜索算法没有找到目标值时,将返回结束迭代器
#include "iostream"
#include "list"
#include "algorithm"
#include "numeric"
int main() {
std::list<int> li(6);
std::iota(li.begin(), li.end(), 0);
auto it{std::find(li.begin(), li.end(), 3)};
if (it == li.end()) {
std::cout << "3 was not found" << '\n';
} else {
li.insert(it, 8);
}
for (int i: li)
std::cout << i << ' '; //输出 0 1 2 8 3 4 5
return 0;
}
std::sort()
不能用于list
容器类,list
容器类有自己的sort()
成员函数