欢迎来到C++标准模板库(STL)的学习之旅!STL是C++的一部分,提供了一套通用的、可重用的模板类和函数,用于处理常见的数据结构和算法。通过掌握STL,您可以大大提高编程效率和代码质量。本文将以通俗易懂的方式,全面介绍C++ STL的各个组成部分及其应用。
vector
list
deque
array
set
map
multiset
multimap
unordered_set
unordered_map
stack
queue
priority_queue
vector
和sort
算法map
进行键值对存储find_if
和Lambda表达式STL(Standard Template Library,标准模板库)是C++标准库的一部分,提供了一套通用的、可重用的模板类和函数,用于处理常见的数据结构(如数组、链表、哈希表等)和算法(如排序、搜索、遍历等)。STL的设计理念是“泛型编程(Generic Programming)”,即编写与类型无关的代码,通过模板参数在编译时指定具体类型。
STL的优势:
STL主要由以下几个部分组成:
容器是STL的核心部分,提供了多种数据结构来存储和组织数据。STL的容器分为以下几类:
序列容器用于存储有序的数据序列,支持元素的插入、删除和访问。
vector
vector
是一个动态数组,支持随机访问,元素在内存中连续存储,适合需要频繁访问元素的场景。
示例:
#include
#include
using namespace std;
int main() {
vector numbers = {1, 2, 3, 4, 5};
// 添加元素
numbers.push_back(6);
// 访问元素
cout << "Element at index 2: " << numbers[2] << endl;
// 遍历
cout << "All elements: ";
for(auto num : numbers) {
cout << num << " ";
}
cout << endl;
return 0;
}
输出:
Element at index 2: 3
All elements: 1 2 3 4 5 6
list
list
是一个双向链表,支持在任意位置高效地插入和删除元素,但不支持随机访问。
示例:
#include
#include
using namespace std;
int main() {
list fruits = {"Apple", "Banana", "Cherry"};
// 添加元素
fruits.push_back("Date");
fruits.push_front("Elderberry");
// 遍历
cout << "Fruits: ";
for(auto it = fruits.begin(); it != fruits.end(); ++it) {
cout << *it << " ";
}
cout << endl;
return 0;
}
输出:
Fruits: Elderberry Apple Banana Cherry Date
deque
deque
(双端队列)支持在头尾高效地插入和删除元素,兼具vector
的随机访问能力。
示例:
#include
#include
using namespace std;
int main() {
deque dq = {10, 20, 30};
// 添加元素
dq.push_back(40);
dq.push_front(5);
// 访问元素
cout << "Element at index 1: " << dq[1] << endl;
// 遍历
cout << "Deque elements: ";
for(auto num : dq) {
cout << num << " ";
}
cout << endl;
return 0;
}
输出:
Element at index 1: 10
Deque elements: 5 10 20 30 40
array
array
是一个固定大小的数组,大小在编译时确定,适合存储固定数量的元素。
示例:
#include
#include
using namespace std;
int main() {
array arr = {1, 2, 3, 4, 5};
// 访问元素
cout << "Element at index 3: " << arr[3] << endl;
// 遍历
cout << "Array elements: ";
for(auto it = arr.begin(); it != arr.end(); ++it) {
cout << *it << " ";
}
cout << endl;
return 0;
}
输出:
Element at index 3: 4
Array elements: 1 2 3 4 5
关联容器用于存储有序的键值对,支持高效的查找、插入和删除操作。
set
set
是一个集合,存储唯一的、有序的元素,自动排序。
示例:
#include
#include
using namespace std;
int main() {
set s = {4, 1, 3, 2};
// 添加元素
s.insert(5);
s.insert(3); // 重复元素不会插入
// 遍历
cout << "Set elements: ";
for(auto it : s) {
cout << it << " ";
}
cout << endl;
return 0;
}
输出:
Set elements: 1 2 3 4 5
map
map
是一个键值对集合,键是唯一的,自动排序。适合需要通过键快速查找值的场景。
示例:
#include
#include
输出:
Alice's age: 30
All ages:
Alice is 30 years old.
Bob is 25 years old.
Charlie is 35 years old.
multiset
和 multimap
multiset
和multimap
允许存储重复的元素或键值对,适用于需要存储多重关联的场景。
示例(multiset
):
#include
#include
using namespace std;
int main() {
multiset ms = {1, 2, 2, 3, 4};
// 添加元素
ms.insert(2);
ms.insert(5);
// 遍历
cout << "Multiset elements: ";
for(auto it : ms) {
cout << it << " ";
}
cout << endl;
return 0;
}
输出:
Multiset elements: 1 2 2 2 3 4 5
无序关联容器使用哈希表实现,提供平均常数时间的查找、插入和删除操作,但不保证元素的顺序。
unordered_set
unordered_set
类似于set
,但不保证元素的顺序,查找速度更快。
示例:
#include
#include
using namespace std;
int main() {
unordered_set us = {4, 1, 3, 2};
// 添加元素
us.insert(5);
us.insert(3); // 重复元素不会插入
// 遍历
cout << "Unordered Set elements: ";
for(auto it : us) {
cout << it << " ";
}
cout << endl;
return 0;
}
输出:
Unordered Set elements: 1 2 3 4 5
unordered_map
unordered_map
类似于map
,但不保证键值对的顺序,查找速度更快。
示例:
#include
#include
using namespace std;
int main() {
unordered_map um;
// 添加键值对
um["Alice"] = 30;
um["Bob"] = 25;
um["Charlie"] = 35;
// 访问元素
cout << "Bob's age: " << um["Bob"] << endl;
// 遍历
cout << "All ages in unordered_map:" << endl;
for(auto it : um) {
cout << it.first << " is " << it.second << " years old." << endl;
}
return 0;
}
输出:
Bob's age: 25
All ages in unordered_map:
Charlie is 35 years old.
Alice is 30 years old.
Bob is 25 years old.
容器适配器是基于已有容器实现的特定数据结构接口,主要包括stack
、queue
和priority_queue
。
stack
stack
是一种后进先出(LIFO)的数据结构,只允许在一端(栈顶)进行插入和删除操作。
示例:
#include
#include
using namespace std;
int main() {
stack s;
// 添加元素
s.push(10);
s.push(20);
s.push(30);
// 遍历栈
cout << "Stack elements: ";
while(!s.empty()) {
cout << s.top() << " ";
s.pop();
}
cout << endl;
return 0;
}
输出:
Stack elements: 30 20 10
queue
queue
是一种先进先出(FIFO)的数据结构,允许在一端(队尾)插入,在另一端(队头)删除。
示例:
#include
#include
using namespace std;
int main() {
queue q;
// 添加元素
q.push("First");
q.push("Second");
q.push("Third");
// 遍历队列
cout << "Queue elements: ";
while(!q.empty()) {
cout << q.front() << " ";
q.pop();
}
cout << endl;
return 0;
}
输出:
Queue elements: First Second Third
priority_queue
priority_queue
是一种优先级队列,元素按优先级顺序排列,默认情况下是最大堆,最大的元素位于队首。
示例:
#include
#include
using namespace std;
int main() {
priority_queue pq;
// 添加元素
pq.push(30);
pq.push(10);
pq.push(20);
// 遍历优先级队列
cout << "Priority Queue elements: ";
while(!pq.empty()) {
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
return 0;
}
输出:
Priority Queue elements: 30 20 10
迭代器是STL中用于访问和遍历容器元素的对象,类似于指针。通过迭代器,您可以在不关心容器内部结构的情况下,遍历和操作容器中的元素。
STL提供了多种迭代器类型,适用于不同的容器和操作:
示例:使用迭代器遍历vector
#include
#include
using namespace std;
int main() {
vector numbers = {1, 2, 3, 4, 5};
// 使用迭代器遍历
cout << "Vector elements: ";
for(vector::iterator it = numbers.begin(); it != numbers.end(); ++it) {
cout << *it << " ";
}
cout << endl;
return 0;
}
输出:
Vector elements: 1 2 3 4 5
示例:使用auto
关键字简化迭代器类型
#include
#include
using namespace std;
int main() {
list fruits = {"Apple", "Banana", "Cherry"};
// 使用auto简化迭代器类型
cout << "List elements: ";
for(auto it = fruits.begin(); it != fruits.end(); ++it) {
cout << *it << " ";
}
cout << endl;
return 0;
}
输出:
List elements: Apple Banana Cherry
STL提供了大量的算法,涵盖排序、搜索、变换、数值计算等操作。这些算法可以与容器和迭代器无缝结合,提高代码的简洁性和效率。
sort
对容器中的元素进行排序,默认按照升序排列。
示例:
#include
#include
#include
using namespace std;
int main() {
vector numbers = {4, 2, 5, 1, 3};
// 排序前
cout << "Before sort: ";
for(auto num : numbers) cout << num << " ";
cout << endl;
// 使用sort算法排序
sort(numbers.begin(), numbers.end());
// 排序后
cout << "After sort: ";
for(auto num : numbers) cout << num << " ";
cout << endl;
return 0;
}
输出:
Before sort: 4 2 5 1 3
After sort: 1 2 3 4 5
find
在容器中查找特定元素,返回指向该元素的迭代器,如果未找到则返回结束迭代器。
示例:
#include
#include
#include
using namespace std;
int main() {
vector names = {"Alice", "Bob", "Charlie", "Diana"};
// 查找"Charlie"
auto it = find(names.begin(), names.end(), "Charlie");
if(it != names.end()) {
cout << "Found: " << *it << endl;
} else {
cout << "Not Found!" << endl;
}
return 0;
}
输出:
Found: Charlie
for_each
对容器中的每个元素应用指定的函数。
示例:
#include
#include
#include
using namespace std;
// 函数对象
struct Print {
void operator()(int x) const {
cout << x << " ";
}
};
int main() {
vector numbers = {1, 2, 3, 4, 5};
// 使用for_each和函数对象
cout << "Elements: ";
for_each(numbers.begin(), numbers.end(), Print());
cout << endl;
return 0;
}
输出:
Elements: 1 2 3 4 5
accumulate
计算容器中所有元素的累加和(需要包含头文件
)。
示例:
#include
#include
#include
using namespace std;
int main() {
vector numbers = {1, 2, 3, 4, 5};
// 计算总和
int sum = accumulate(numbers.begin(), numbers.end(), 0);
cout << "Sum: " << sum << endl;
return 0;
}
输出:
Sum: 15
函数对象是重载了operator()
的类,可以像函数一样调用。它们通常用于算法中传递自定义操作。
示例:
#include
#include
#include
using namespace std;
// 函数对象,用于打印元素
struct Print {
void operator()(int x) const {
cout << x << " ";
}
};
int main() {
vector numbers = {1, 2, 3, 4, 5};
// 使用for_each和函数对象
cout << "Elements: ";
for_each(numbers.begin(), numbers.end(), Print());
cout << endl;
return 0;
}
输出:
Elements: 1 2 3 4 5
Lambda表达式是一种轻量级的函数对象,可以在需要函数的地方定义匿名函数,简化代码。
示例:
#include
#include
#include
using namespace std;
int main() {
vector numbers = {1, 2, 3, 4, 5};
// 使用for_each和Lambda表达式
cout << "Elements: ";
for_each(numbers.begin(), numbers.end(), [](int x) {
cout << x << " ";
});
cout << endl;
// 使用sort和Lambda表达式进行自定义排序(降序)
sort(numbers.begin(), numbers.end(), [](int a, int b) -> bool {
return a > b;
});
cout << "Sorted (descending): ";
for(auto num : numbers) cout << num << " ";
cout << endl;
return 0;
}
输出:
Elements: 1 2 3 4 5
Sorted (descending): 5 4 3 2 1
通过实际的代码示例,深入理解STL的应用。
vector
和sort
算法示例:
#include
#include
#include
using namespace std;
int main() {
// 创建并初始化vector
vector nums = {4, 2, 5, 1, 3};
// 打印原始元素
cout << "Original vector: ";
for(auto num : nums) cout << num << " ";
cout << endl;
// 排序
sort(nums.begin(), nums.end());
// 打印排序后的元素
cout << "Sorted vector: ";
for(auto num : nums) cout << num << " ";
cout << endl;
return 0;
}
输出:
Original vector: 4 2 5 1 3
Sorted vector: 1 2 3 4 5
map
进行键值对存储示例:
#include
#include
输出:
Alice's age: 30
All ages:
Alice is 30 years old.
Bob is 26 years old.
Charlie is 35 years old.
find_if
和Lambda表达式示例:
#include
#include
#include
using namespace std;
int main() {
vector numbers = {10, 20, 30, 40, 50};
// 查找第一个大于25的元素
auto it = find_if(numbers.begin(), numbers.end(), [](int x) {
return x > 25;
});
if(it != numbers.end()) {
cout << "First number > 25: " << *it << endl;
} else {
cout << "No number > 25 found." << endl;
}
return 0;
}
输出:
First number > 25: 30
为了充分利用STL的优势,以下是一些最佳实践建议:
不同的容器适用于不同的场景:
vector
:适合需要频繁随机访问和在末尾添加元素的场景。list
:适合需要频繁在任意位置插入和删除元素的场景。deque
:适合需要在头尾进行高效插入和删除,并且需要随机访问的场景。map
:适合需要通过键快速查找值的场景。unordered_map
:适合需要高效查找但不关心顺序的场景。通过使用引用或指针,避免在容器和算法中进行不必要的拷贝操作,提升性能。
示例:使用引用遍历vector
#include
#include
using namespace std;
int main() {
vector nums = {1, 2, 3, 4, 5};
// 使用引用避免拷贝
for(auto &num : nums) {
num *= 2; // 修改原始元素
}
// 打印结果
for(auto num : nums) cout << num << " ";
cout << endl;
return 0;
}
输出:
2 4 6 8 10
STL提供了丰富的算法库,通过算法可以大大简化代码并提升效率。
示例:使用transform
算法进行元素变换
#include
#include
#include
using namespace std;
int main() {
vector nums = {1, 2, 3, 4, 5};
vector squared(nums.size());
// 使用transform算法计算平方
transform(nums.begin(), nums.end(), squared.begin(), [](int x) {
return x * x;
});
// 打印结果
cout << "Squared numbers: ";
for(auto num : squared) cout << num << " ";
cout << endl;
return 0;
}
输出:
Squared numbers: 1 4 9 16 25
C++标准模板库(STL)为开发者提供了一套高效、可重用的工具,用于处理常见的数据结构和算法。通过熟练掌握STL的容器、迭代器、算法以及函数对象,您可以编写出更简洁、更高效的代码。以下是本文的关键要点:
通过不断练习和实际应用,您将能够充分发挥STL的优势,提升C++编程技能。
cppreference.com
GeeksforGeeks
LearnCPP.com
YouTube - The Cherno C++ Series
Udemy
LeetCode
HackerRank
Codeforces