C++进阶教程:C++ 标准模板库初学者指南("C++进阶必备:标准模板库(STL)新手入门指南")
原创
一、引言
在C++的学习过程中,标准模板库(Standard Template Library,简称STL)是一个非常重要的部分。STL为C++程序员提供了一系列模板化的数据结构和算法,允许代码更加简洁、高效。本文将为您介绍STL的基本概念、常用组件及其使用方法,帮助新手飞速入门。
二、STL概述
STL重点包括以下几个部分:
- 容器(Containers):提供了一种存储数据集合的方法。
- 迭代器(Iterators):提供了一种访问容器中元素的方法。
- 算法(Algorithms):提供了一系列用于操作数据的函数。
- 函数对象(Function Objects):是一种特殊的函数,可以存储在容器中并像普通对象一样使用。
- 适配器(Adapters):用于扩展或修改已有容器或算法的功能。
三、STL容器
STL提供了多种容器,包括序列容器、相关性容器和适配器容器。下面分别介绍它们的用法。
3.1 序列容器
序列容器包括vector、deque、list、forward_list和array。下面分别介绍它们的特性和用法。
3.1.1 vector
vector是一个动态数组,可以按照需要动态地改变大小。
#include
#include
int main() {
std::vector
v; v.push_back(1);
v.push_back(2);
v.push_back(3);
for (int i = 0; i < v.size(); ++i) {
std::cout << v[i] << " ";
}
std::cout << std::endl;
return 0;
}
3.1.2 deque
deque是一个双端队列,可以在两端插入和删除元素。
#include
#include
int main() {
std::deque
d; d.push_front(1);
d.push_back(2);
d.push_back(3);
for (auto it = d.begin(); it != d.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
3.1.3 list
list是一个双向链表,可以在任意位置插入和删除元素。
#include
#include
int main() {
std::list
l = {1, 2, 3}; for (auto it = l.begin(); it != l.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
3.1.4 forward_list
forward_list是一个单向链表,仅拥护单向遍历。
#include
#include
int main() {
std::forward_list
fl = {1, 2, 3}; for (auto it = fl.begin(); it != fl.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
3.1.5 array
array是一个固定大小的数组,类似于C风格的数组。
#include
#include
int main() {
std::array
a = {1, 2, 3}; for (int i = 0; i < a.size(); ++i) {
std::cout << a[i] << " ";
}
std::cout << std::endl;
return 0;
}
3.2 相关性容器
相关性容器包括set、multiset、map、multimap、unordered_set、unordered_multiset、unordered_map和unordered_multimap。下面分别介绍它们的特性和用法。
3.2.1 set
set是一个有序集合,存储唯一的元素。
#include
#include
int main() {
std::set
s = {1, 2, 2, 3}; for (auto it = s.begin(); it != s.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
3.2.2 multiset
multiset是一个有序集合,可以存储多个相同的元素。
#include
#include
int main() {
std::multiset
ms = {1, 2, 2, 3}; for (auto it = ms.begin(); it != ms.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
3.2.3 map
map是一个有序映射,存储键值对。
#include
#include
int main() {
std::map
m = {{1, "one"}, {2, "two"}, {3, "three"}}; for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
3.2.4 multimap
multimap是一个有序映射,可以存储多个具有相同键的元素。
#include
#include
int main() {
std::multimap
mm = {{1, "one"}, {2, "two"}, {2, "two2"}, {3, "three"}}; for (auto it = mm.begin(); it != mm.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
3.2.5 unordered_set
unordered_set是一个无序集合,存储唯一的元素。
#include
#include
int main() {
std::unordered_set
us = {1, 2, 2, 3}; for (auto it = us.begin(); it != us.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
3.2.6 unordered_multiset
unordered_multiset是一个无序集合,可以存储多个相同的元素。
#include
#include
int main() {
std::unordered_multiset
ums = {1, 2, 2, 3}; for (auto it = ums.begin(); it != ums.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
3.2.7 unordered_map
unordered_map是一个无序映射,存储键值对。
#include
#include
int main() {
std::unordered_map
um = {{1, "one"}, {2, "two"}, {3, "three"}}; for (auto it = um.begin(); it != um.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
3.2.8 unordered_multimap
unordered_multimap是一个无序映射,可以存储多个具有相同键的元素。
#include
#include
int main() {
std::unordered_multimap
umm = {{1, "one"}, {2, "two"}, {2, "two2"}, {3, "three"}}; for (auto it = umm.begin(); it != umm.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
3.3 适配器容器
适配器容器包括stack、queue、priority_queue、stack适配器、queue适配器和priority_queue适配器。下面分别介绍它们的特性和用法。
3.3.1 stack
stack是一个后进先出(LIFO)的容器。
#include
#include
int main() {
std::stack
s; s.push(1);
s.push(2);
s.push(3);
while (!s.empty()) {
std::cout << s.top() << " ";
s.pop();
}
std::cout << std::endl;
return 0;
}
3.3.2 queue
queue是一个先进先出(FIFO)的容器。
#include
#include
int main() {
std::queue
q; q.push(1);
q.push(2);
q.push(3);
while (!q.empty()) {
std::cout << q.front() << " ";
q.pop();
}
std::cout << std::endl;
return 0;
}
3.3.3 priority_queue
priority_queue是一个优先队列,元素按照优先级排序。
#include
#include
#include
int main() {
std::priority_queue
pq; pq.push(1);
pq.push(3);
pq.push(2);
while (!pq.empty()) {
std::cout << pq.top() << " ";
pq.pop();
}
std::cout << std::endl;
return 0;
}
四、STL迭代器
迭代器是一种抽象指针,用于访问容器中的元素。STL提供了多种迭代器,包括输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。下面分别介绍它们的用法。
4.1 输入迭代器
输入迭代器只能用于读取元素,不能修改元素。
#include
#include
int main() {
std::vector
v = {1, 2, 3}; std::vector
::iterator it = v.begin(); while (it != v.end()) {
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
return 0;
}
4.2 输出迭代器
输出迭代器只能用于写入元素,不能读取元素。
#include
#include
int main() {
std::vector
v = {1, 2, 3}; std::vector
::iterator it = v.begin(); std::cout << "Output iterator: ";
while (it != v.end()) {
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
return 0;
}
4.3 前向迭代器
前向迭代器可以读取和修改元素,但不能双向遍历。
#include
#include
int main() {
std::list
l = {1, 2, 3}; std::list
::iterator it = l.begin(); while (it != l.end()) {
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
return 0;
}
4.4 双向迭代器
双向迭代器可以读取和修改元素,并拥护双向遍历。
#include
#include
int main() {
std::deque
d = {1, 2, 3}; std::deque
::iterator it = d.begin(); while (it != d.end()) {
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
return 0;
}
4.5 随机访问迭代器
随机访问迭代器可以读取和修改元素,并拥护随机访问。
#include
#include
int main() {
std::vector
v = {1, 2, 3}; std::vector
::iterator it = v.begin(); std::cout << "Element at index 1: " << v[1] << std::endl;
return 0;
}
五、STL算法
STL算法提供了一系列用于操作数据的函数,包括排序、查找、替换、合并、分区等。下面介绍一些常用的算法。
5.1 排序算法
sort算法可以对容器内的元素进行排序。
#include
#include
#include
int main() {
std::vector
v = {3, 1, 2}; std::sort(v.begin(), v.end());
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
5.2 查找算法
find算法可以在容器中查找特定元素。
#include
#include
#include
int main() {
std::vector
v = {1, 2, 3, 4, 5}; auto it = std::find(v.begin(), v.end(), 3);
if (it != v.end()) {
std::cout << "Element found: " << *it << std::endl;
} else {
std::cout << "Element not found" << std::endl;
}
return 0;
}
5.3 替换算法
replace算法可以将容器中的元素替换为另一个值。
#include
#include
#include
int main() {
std::vector
v = {1, 2, 3, 4, 5}; std::replace(v.begin(), v.end(), 2, 10);
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
5.4 合并算法
merge算法可以将两个有序容器合并为一个有序容器。
#include
#include
#include
int main() {
std::vector
v1 = {1, 3, 5}; std::vector
v2 = {2, 4, 6}; std::vector
v3; std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v3));
for (auto it = v3.begin(); it != v3.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
5.5 分区算法
partition算法可以将容器中的元素按照条件分为两个部分。
#include
#include
#include
bool is_odd(int x) {
return x % 2 != 0;
}
int main() {
std::vector
v = {1, 2, 3, 4, 5}; std::partition(v.begin(), v.end(), is_odd);
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
六、STL函数对象
函数对象是一种特殊的函数,可以存储在容器中并像普通对象一样使用。下面介绍两种常用的函数对象。
6.1 函数对象
函数对象是一个重载了operator()的类。
#include
#include
#include
class Print {
public:
void operator()(int x) {
std::cout << x << " ";
}
};
int main() {
std::