C++ STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数, 这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。
STL
- 容器(Containers):vector、list、deque、queue、stack、set、map等。
- 迭代器(Iterators):用于遍历容器中的元素。
- 算法(Algorithms):包括排序、查找、统计、变换等一系列常用算法。
- 函数对象(Function Objects):可用于算法中的比较、操作等。
- 适配器(Adapters):包括容器适配器、迭代器适配器、函数适配器等,用于将现有的组件转化为其他需要的形式。
- 其他组件:包括数值计算、随机数、日期和时间、文件操作等
容器
- 序列式容器(Sequential Containers):按照线性方式组织元素,包括vector、list、deque等。
- 关联式容器(Associative Containers):按照键值方式组织元素,包括set、multiset、map、multimap等。
- 容器适配器(Container Adapters):用于将现有的容器转换为其他形式,包括stack、queue、priority_queue等。
vector
向量容器(一个 C++ 标准的模板),vector是一个动态数组,可以在运行时动态增加或减少其大小
#include <iostream>
#include <vector>
using namespace std;
// g++ -std=c++11 stl_vector_test.cpp
int main()
{
vector<int> v; // 创建一个空的int类型vector
vector<string> v2(10); // 创建一个包含10个空字符串的vector
vector<double> v3(5, 2.5); // 创建一个包含5个值为2.5的double类型vector
v.push_back(10); // 向vector尾部添加一个元素
v.insert(v.begin(), 5); // 在vector头部插入一个元素
int x = v[0]; // 获取vector中第一个元素的值
int y = v.at(1); // 获取vector中第二个元素的值
v[0] = 20; // 修改vector中第一个元素的值为20
v.at(1) = 30; // 修改vector中第二个元素的值为30
v.pop_back(); // 删除vector尾部的元素
v.erase(v.begin()); // 删除vector头部的元素
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
vector<int>::iterator iter = v.begin();
while (iter != v.end())
{
cout << *iter << endl;
iter++;
}
v.clear(); // 删除vector中所有的元素
return 0;
}
list
list是一个双向链表,可以在运行时动态增加或删除节点
#include <iostream>
#include <list>
using namespace std;
// g++ -std=c++11 stl_list_test.cpp
int main()
{
list<int> lst; // 创建一个空的int类型list
list<string> lst2(10); // 创建一个包含10个空字符串的list
list<double> lst3(5, 2.5); // 创建一个包含5个值为2.5的double类型list
lst.push_back(10); // 向list尾部添加一个元素
lst.push_front(5); // 向list头部添加一个元素
lst.insert(lst.begin(), 3); // 在list头部插入一个元素
int x = lst.front(); // 获取list中第一个元素的值
int y = lst.back(); // 获取list中最后一个元素的值
lst.front() = 20; // 修改list中第一个元素的值为20
lst.back() = 30; // 修改list中最后一个元素的值为30
int size = lst.size(); // 获取list中元素的个数
for (list<int>::iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
lst.pop_front(); // 删除list头部的元素
lst.pop_back(); // 删除list尾部的元素
lst.erase(lst.begin()); // 删除list头部的元素
lst.clear(); // 删除list中所有的元素
return 0;
}
deque
deque是一个双端队列,可以在运行时动态增加或删除队首和队尾的元素;
#include <iostream>
#include <deque>
using namespace std;
// g++ -std=c++11 stl_deque_test.cpp
int main()
{
deque<int> dq; // 创建一个空的int类型deque
deque<string> dq2(10); // 创建一个包含10个空字符串的deque
deque<double> dq3(5, 2.5); // 创建一个包含5个值为2.5的double类型deque
dq.push_back(10); // 向deque尾部添加一个元素
dq.push_front(5); // 向deque头部添加一个元素
int x = dq.front(); // 获取deque中第一个元素的值
int y = dq.back(); // 获取deque中最后一个元素的值
dq.front() = 20; // 修改deque中第一个元素的值为20
dq.back() = 30; // 修改deque中最后一个元素的值为30
dq.pop_front(); // 删除deque头部的元素
dq.pop_back(); // 删除deque尾部的元素
int size = dq.size(); // 获取deque中元素的个数
for (deque<int>::iterator it = dq.begin(); it != dq.end(); it++)
{
cout << *it << " ";
}
dq.clear(); // 删除deque中所有的元素
}
list 和 deque 的区别
- list是一个双向链表,每个元素都有前驱和后继指针,因此它的元素在内存中不是连续存储的。
- deque是一个双端队列,内部实现是一个环形的缓冲区,因此它的元素在内存中是连续存储的。
- 由于deque的元素在内存中是连续存储的,因此它支持随机访问,即可以像数组一样通过下标直接访问元素。而list不支持随机访问,必须通过迭代器遍历才能访问元素
- 由于list的元素在内存中不是连续存储的,因此在插入和删除元素时,只需要修改前后节点的指针即可,不需要移动其他元素,因此list的插入和删除性能比deque更高
- 而deque在插入和删除元素时,由于需要维护缓冲区的连续性,因此可能需要移动其他元素,因此其插入和删除性能相对较低
- 由于list支持高效的插入和删除操作,因此适合于元素数量变化频繁的场景; 而deque支持随机访问,适合于需要频繁访问元素的场景。
map
map是一种关联容器,它提供了一种将键映射到值的方式
#include <iostream>
#include <map>
using namespace std;
// g++ -std=c++11 stl_map_test.cpp
int main()
{
map<string, int> m; // 创建一个空的string到int的map
m["apple"] = 10; // 将键"apple"映射到值10
m.insert(make_pair("banana", 20)); // 将键"banana"映射到值20
int x = m["apple"]; // 获取键"apple"对应的值
int y = m.at("banana"); // 获取键"banana"对应的值
m["apple"] = 20; // 将键"apple"对应的值修改为20
m.at("banana") = 30; // 将键"banana"对应的值修改为30
m.erase("apple"); // 删除键为"apple"的元素
int size = m.size(); // 获取map中元素的个数
for (map<string, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << it->first << ": " << it->second << endl;
}
if (m.count("apple"))
{
cout << "apple exists" << endl;
}
return 0;
}
queue
queue是一种先进先出的容器,可以在队尾添加元素,在队头删除元素
#include <queue>
#include <iostream>
using namespace std;
// g++ -std=c++11 stl_queue_test.cpp
int main()
{
queue<int> q; // 创建一个空的int类型queue
q.push(10); // 向queue尾部添加一个元素
int x = q.front(); // 获取queue头部的元素
int y = q.back(); // 获取queue尾部的元素
// q.pop(); // 删除queue头部的元素
int size = q.size(); // 获取queue中元素的个数
if (q.empty())
{
cout << "queue is empty" << endl;
}
while (!q.empty())
{
int x = q.front();
cout << x << " ";
q.pop();
}
}
stack
stack 是一种后进先出的容器,可以在栈顶添加元素,在栈顶删除元素
#include <iostream>
#include <stack>
using namespace std;
// g++ -std=c++11 stl_stack_test.cpp
int main()
{
stack<int> s; // 创建一个空的int类型stack
s.push(10); // 向stack顶部添加一个元素
int x = s.top(); // 获取stack顶部的元素
s.pop(); // 删除stack顶部的元素
int size = s.size(); // 获取stack中元素的个数
if (s.empty())
{
cout << "stack is empty" << endl;
}
while (!s.empty())
{
int x = s.top();
cout << x << " ";
s.pop();
}
return 0;
}
set
set是一种关联容器,用于存储不重复的元素,且元素自动按照一定的规则排序
#include <iostream>
#include <set>
using namespace std;
// g++ -std=c++11 stl_set_test.cpp
int main()
{
set<int> s; // 创建一个空的int类型set
s.insert(10); // 向set中插入一个元素
set<int>::iterator it = s.find(10); // 查找set中是否存在值为10的元素
if (it != s.end())
{
cout << "item exists" << endl;
}
s.erase(10); // 删除set中值为10的元素
int size = s.size(); // 获取set中元素的个数
if (s.empty())
{
cout << "set is empty" << endl;
}
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
return 0;
}
迭代器
迭代器(Iterator)用于遍历容器中的元素。迭代器是一种类似于指针的对象,可以指向容器中的某个元素,并支持类似于指针的操作,如解引用、自增等
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {1, 2, 3, 4, 5}; // C++11特性, 编译时: g++ -std=c++11 source.cpp
auto it = v.begin(); // 获取vector的起始迭代器
// 迭代器的比较:
auto end = v.end();
while (it != end)
{
int x = *it; // 获取迭代器指向的元素的值
cout << x << " ";
it++; // 将迭代器指向下一个元素
}
// 迭代器的逆向遍历:
auto it2 = v.rbegin(); // 获取vector的逆向迭代器
auto end2 = v.rend();
while (it2 != end2)
{
cout << *it2 << " ";
it2++;
}
return 0;
}
g++ -std=c++11 source.cpp && ./a.out
算法
C++ STL(Standard Template Library)提供了多种算法(Algorithms),包括以下几类:
- 非修改性序列算法(Non-modifying Sequence Algorithms):不会修改序列中的元素,包括查找、计数、比较等。
- 修改性序列算法(Modifying Sequence Algorithms):可以修改序列中的元素,包括排序、拷贝、替换等。
- 排列组合算法(Permutation Algorithms):用于生成序列的所有可能排列或组合。
- 数值算法(Numeric Algorithms):用于对序列中的数值进行计算和操作,包括求和、平均数、内积等。
- 堆算法(Heap Algorithms):用于操作堆数据结构,包括建堆、堆排序等。
- 其他算法:包括特定于区间的算法、特定于集合的算法等。
#include <iostream>
#include <vector>
using namespace std;
// g++ -std=c++11 stl_algorithm_test.cpp && ./a.out
int main()
{
vector<int> v = {1, 2, 3, 4, 5};
auto it = find(v.begin(), v.end(), 3); // 查找值为3的元素
if (it != v.end())
{
cout << "3 exists" << endl;
}
vector<int> v2 = {3, 1, 4, 1, 5, 9, 2, 6};
sort(v2.begin(), v2.end()); // 对序列进行排序
for (auto x : v2)
{
cout << x << " ";
}
return 0;
}