vector
-
变长数组,是使用倍增的思想实现的,当空间不够时,当前空间大小不够用时申请当前空间二倍的空间,再将原数组中内容 copy 过去。系统为一段程序分配空间时所需时间与空间的大小无关,与申请的次数有关,因此优化时应当优先考虑减少申请次数。
-
使用它时需要包含头文件:
#include<vector>;
vector 初始化:
(1) vector<int> a(10); //定义了10个整型元素的向量
(2) vector<int> a(10, 3); //定义了10个整型元素的向量,且给出每个元素的初值为3
(3) vector<int> a(b); //用b向量来创建a向量,整体复制性赋值 (
(4) vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
(5) int b[7]={1,2,3,4,5,9,8}; vector<int> a(b,b+7); //从数组中获得初值
vector对象的几个重要操作,举例说明如下:
a[i]; //返回a的第i个元素,当且仅当a[i]存在2013-12-07
a.size(); //返回a中元素的个数;
a.empty(); //判断a是否为空,空则返回ture,不空则返回false
a.clear(); //清空a中的元素
a.back(); //返回a的最后一个元素
a.front(); //返回a的第一个元素
a.pop_back(); //删除a向量的最后一个元素
a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5
a.erase(a.begin()+1,a.begin()+3); //删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+ 3(不包括它)
a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a
a.assign(4,2); //是a只含4个元素,且每个元素为2
a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
a.insert(a.begin()+1,3,5); //在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
a.insert(a.begin()+1,b+3,b+6); //b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),如b为1,2,3,4,5,9,8 ,插入元素后为1,4,5,9,2,3,4,5,9,8
a.capacity(); //返回a在内存中总共可以容纳的元素个数
a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机
a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2
a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.这种操作只有在需要给a添加大量数据的时候才 显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能)
a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
顺序访问vector的几种方式,举例说明如下:
向向量a中添加元素
vector<int> a;
for(int i=0;i<10;i++)
a.push_back(i);
也可以从数组中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=1;i<=4;i++)
b.push_back(a[i]);
也可以从现有向量中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
vector<int> c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();it++)
b.push_back(*it);
也可以从文件中读取元素向向量中添加
ifstream in("data.txt");
vector<int> a;
for(int i; in>>i)
a.push_back(i);
从向量中读取元素
1、通过下标方式读取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(int i=0;i<=b.size()-1;i++) cout<<b[i]<<" ";
2、通过遍历器方式读取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(vector<int>::iterator it=b.begin();it!=b.end();it++)
cout<<*it<<" ";
stl提供的几种重要的算法
使用时需要包含头文件:#include<algorithm>
sort(a.begin(),a.end());
//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列reverse(a.begin(),a.end());
//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1copy(a.begin(),a.end(),b.begin()+1);
//把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开 始复制,覆盖掉原有元素find(a.begin(),a.end(),10);
//在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
string:
简介:C++ STL(标准模板库)中的std::string是一个用于操作字符串的类,提供了许多方便的功能和方法,使得处理文本数据变得更加容易和高效。
std::string的一些重要特性和用法:
- 动态大小: std::string 允许在运行时根据需要动态调整字符串的大小,无需手动分配或释放内存。
- 字符访问: 可以像访问数组一样通过索引访问字符串中的字符。例如,str[0]表示字符串中的第一个字符。
- 字符串连接: 使用操作符 + 可以将两个字符串连接起来,也可以使用 append() 方法将一个字符串追加到另一个字符串的末尾。
- 字符串比较: 提供了比较操作符和方法,可以进行字符串的大小比较,例如 ==、!=、<、>等。
- 子串提取: 可以使用 substr() 方法从字符串中提取子串。
- 查找和替换: 提供了查找和替换子串的方法,如 find()、replace() 等。
- 字符操作: std::string 支持插入、删除和替换字符的方法,使得对字符串进行编辑操作更加方便。
- C风格字符串转换: 可以使用 c_str() 方法将 std::string 转换为C风格的字符串(以null结尾的字符数组)。
- 迭代器支持: std::string 支持迭代器,允许使用循环遍历字符串中的字符。
- 长度和容量查询: 可以使用 length() 或 size() 方法获取字符串的长度,以及使用 capacity() 方法查询字符串的内部缓冲区容量。
- 注意printf无法直接输出string,需要使用c_str()方法转换一下。例如
printf("%s", a.c_str());
示例代码
#include <iostream>
#include <string>
int main() {
std::string greeting = "Hello, ";
std::string name = "John";
// 字符串连接
std::string message = greeting + name;
// 字符串长度和容量查询
std::cout << "Length: " << message.length() << std::endl;
std::cout << "Capacity: " << message.capacity() << std::endl;
// 字符串迭代
for (char c : message) {
std::cout << c << " ";
}
std::cout << std::endl;
// 子串提取
std::string substring = message.substr(7, 4); // 从第7个字符开始提取4个字符
std::cout << "Substring: " << substring << std::endl;
return 0;
}
结果如下:
Length: 11
Capacity: 14
H e l l o , J o h n
Substring: John
pair
std::pair 是一个模板类,用于将两个值组合成一个单元,其中每个值可以是不同的类型。std::pair 通常用于在需要将两个值作为一个单元处理的情况,例如在映射(map)或关联容器中存储键值对。
重要特性和用法:
创建 std::pair:
可以使用 std::make_pair() 函数或直接使用构造函数来创建一个 std::pair 对象。例如:
pair<int, double> myPair = make_pair(10, 3.14);
成员访问:
可以使用 first 和 second 成员来访问 pair 中的第一个值和第二个值。例如:
int firstValue = myPair.first;
double secondValue = myPair.second;
比较操作:
pair 支持比较操作,按照字典顺序比较。即先比较第一个值,如果相同再比较第二个值。
在容器中使用:
pair 可以作为容器元素存储在各种容器中,如 map、unordered_map 等。
函数返回值: 可以在函数中使用 pair 返回多个值。
以下是一个示例代码,展示了如何使用 pair:
#include <iostream>
#include <utility> // for pair
using namespace std;
int main() {
// 创建一个 pair
pair<int, string> student = make_pair(101, "Alice");
// 访问 pair 的成员
int id = student.first;
string name = student.second;
cout << "Student ID: " << id << ", Name: " << name << endl;
// 在容器中存储 pairs
pair<int, double> point1 = make_pair(3, 4.5);
pair<int, double> point2 = make_pair(0, 2.1);
pair<int, double> point3 = make_pair(-1, -0.5);
cout << "Comparing point1 and point2: " << (point1 < point2) << endl;
return 0;
}
结果
Student ID: 101, Name: Alice
Comparing point1 and point2: 0
在这个示例中,我们创建了一个 pair 表示学生的 ID 和名字,然后访问了它的成员。
我们还创建了几个存储点坐标的 pair,并比较了其中两个 pair。
queue
std::queue
是一个容器适配器,它基于其他底层容器(默认使用 std::deque
)实现的队列数据结构。队列是一种先进先出(FIFO)的数据结构,适用于在一端插入元素,另一端删除元素的场景。std::queue 提供了一组操作,使得在队列的尾部添加元素,从队列的头部删除元素。
重要特性和用法:
-
先进先出:
std::queue
是先进先出的数据结构,插入的元素会在队列的末尾,而删除操作会在队列的头部进行。 -
队列操作:
std::queue
提供了 push() 方法用于在队列尾部插入元素,以及 pop() 方法用于从队列头部删除元素。 -
队列的头部元素: 使用
front()
方法可以获取队列头部的元素,但不会将元素从队列中删除。 -
队列的尾部元素: 由于
std::queue
本质上是一个适配器,它没有提供直接访问队列尾部元素的方法。但是,可以通过底层容器的方法来获取尾部元素,如std::deque::back()
。
扩展
在算法中,队列常常被用于广度优先搜索(BFS)等需要遍历树状或图状结构的场景。以下是一些在算法中使用队列的技巧:
-
BFS(广度优先搜索): 在树或图的 BFS 算法中,队列常用于存储待处理的节点。算法从起始节点开始,逐层遍历,并将每一层的子节点依次放入队列中,以确保按照层级顺序进行遍历。
-
层次遍历: 类似于 BFS,队列也可以用于树的层次遍历。从根节点开始,将每个节点的子节点按顺序放入队列,然后逐个处理队列中的节点。
-
任务调度: 队列可以用于实现任务调度。例如,你可以将需要按照一定顺序执行的任务放入队列中,然后逐个从队列中取出执行。
-
滑动窗口问题: 在滑动窗口类型的问题中,队列可以用来维护一个动态窗口内的元素,以便在窗口滑动时有效地添加和删除元素。
以下是一个示例代码,展示了如何使用std::queue来解决广度优先搜索问题(BFS):
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
void bfs(const vector<vector<int>>& graph, int start) {
queue<int> q;
vector<bool> visited(graph.size(), false);
q.push(start);
visited[start] = true;
while (!q.empty()) {
int current = q.front();
q.pop();
cout << current << " ";
for (int neighbor : graph[current]) {
if (!visited[neighbor]) {
q.push(neighbor);
visited[neighbor] = true;
}
}
}
}
int main() {
// 构建一个图的邻接表表示
vector<vector<int>> graph = {{1, 2}, {0, 3, 4}, {0, 4}, {1, 4, 5}, {1, 2, 3}, {3}};
cout << "BFS traversal starting from node 0: ";
bfs(graph, 0);
return 0;
}
结果:
BFS traversal starting from node 0: 0 1 2 3 4 5
在这个示例中,std::queue用于在BFS算法中维护待处理的节点。
priority_queue
简介
在 C++ 的标准模板库(STL)中,std::priority_queue 是一个容器适配器,用于实现优先队列数据结构。与普通队列不同,优先队列中的元素具有优先级,优先级高的元素总是位于队列的前面。std::priority_queue 使用堆(heap)实现,以确保具有最高优先级的元素在队列的顶部。
基本操作
top()
:访问队列头部元素(具有最高优先级的元素)。empty()
:检查队列是否为空。size()
:返回队列内元素的个数。push()
:插入元素到队尾并按照优先级重新排序。emplace()
:原地构造一个元素并插入队列。pop()
:移除队头元素。
默认优先级
默认情况下,std::priority_queue
使用降序方式存储元素,也就是最大元素位于队列的顶部。可以通过自定义比较函数来改变排序规则。
自定义比较函数
可以通过提供自定义的比较函数,来改变元素的排序规则。比较函数可以是函数指针、函数对象或 Lambda 表达式。例如:
// 升序队列
priority_queue<int, vector<int>, greater<int>> minHeap;
// 降序队列
priority_queue<int, vector<int>, less<int>> maxHeap;
示例代码:
#include <iostream>
#include <queue>
using namespace std;
int main() {
// 默认为最大堆
priority_queue<int> maxHeap;
// 最小堆
priority_queue<int, vector<int>, greater<int>> minHeap;
for (int i = 0; i < 5; i++) {
maxHeap.push(i);
minHeap.push(i);
}
cout << "Max Heap: ";
while (!maxHeap.empty()) {
cout << maxHeap.top() << ' ';
maxHeap.pop();
}
cout << "\nMin Heap: ";
while (!minHeap.empty()) {
cout << minHeap.top() << ' ';
minHeap.pop();
}
cout << endl;
return 0;
}
输出
Max Heap: 4 3 2 1 0
Min Heap: 0 1 2 3 4
自定义类型的使用
#include <iostream>
#include <queue>
using namespace std;
// 自定义比较函数
struct Compare {
bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
return a.first > b.first; // 小顶堆
}
};
int main() {
priority_queue<pair<int, int>, vector<pair<int, int>>, Compare> customQueue;
pair<int, int> a = make_pair(3, 5);
pair<int, int> b = make_pair(1, 2);
pair<int, int> c = make_pair(2, 4);
customQueue.push(a);
customQueue.push(b);
customQueue.push(c);
cout << "Custom Priority Queue: ";
while (!customQueue.empty()) {
cout << "(" << customQueue.top().first << ", " << customQueue.top().second << ") ";
customQueue.pop();
}
cout << endl;
return 0;
}
输出
Custom Priority Queue: (1, 2) (2, 4) (3, 5)
总结
std::priority_queue
是 C++ STL 提供的用于实现优先队列的容器适配器。通过提供自定义比较函数,可以调整元素的排序规则,从而满足不同的业务需求。优先队列在许多算法和数据结构中都有广泛的应用,如 Dijkstra 算法等。
stack
std::stack
是一个容器适配器,用于实现堆栈(stack
)数据结构。堆栈是一种后进先出(FIFO)的数据结构,类似于将元素堆叠在一起,最后放入的元素首先被取出。std::stack
通过底层容器来实现堆栈的功能,默认使用 std::deque
作为底层容器。
重要特性和用法:
-
栈操作:
std::stack
提供了push()
方法用于将元素压入栈顶,以及pop()
方法用于从栈顶弹出元素。 -
访问栈顶元素: 使用
top()
方法可以访问栈顶的元素,但不会将元素从栈中移除。 -
栈的大小: 使用
size()
方法可以获取栈中元素的数量。 -
判断栈是否为空: 使用
empty()
方法可以检查栈是否为空。
示例代码:
#include <iostream>
#include <stack>
int main() {
std::stack<int> mystack;
// 压入元素
mystack.push(10);
mystack.push(20);
mystack.push(30);
std::cout << "Top element: " << mystack.top() << std::endl;
// 弹出栈顶元素
mystack.pop();
std::cout << "Top element after pop: " << mystack.top() << std::endl;
std::cout << "Stack size: " << mystack.size() << std::endl;
std::cout << "Is stack empty? " << (mystack.empty() ? "Yes" : "No") << std::endl;
return 0;
}
结果
Top element: 30
Top element after pop: 20
Stack size: 2
Is stack empty? No
在这个示例中,我们创建了一个 std::stack,压入了一些元素,然后访问栈顶元素、弹出元素,并查看栈的大小和是否为空。
std::stack 是一个方便的容器适配器,适用于需要实现堆栈数据结构的场景。
deque
介绍
std::deque
(双端队列,全名为 “double-ended queue”)是一个容器,用于存储可以动态大小调整的元素序列。std::deque
允许在两端进行高效的插入和删除操作,同时提供了随机访问元素的能力。
重要特性和用法:
-
双端操作:
std::deque
允许在两端进行插入和删除操作,即在队首和队尾都可以高效地执行push
和pop
操作。 -
随机访问: 与
std::vector
类似,std::deque
也支持随机访问,可以通过下标或迭代器访问元素。 -
动态大小:
std::deque
的大小可以根据需要自动调整,无需提前指定容器大小。 -
高效插入和删除: 在队首和队尾进行插入和删除操作的时间复杂度为常数时间 O(1),这使得
std::deque
在需要频繁在两端进行操作时更具优势。 -
分段存储:
std::deque
内部采用多个分段进行存储,这允许在不移动元素的情况下进行动态大小调整。
示例代码:
#include <iostream>
#include <deque>
int main() {
std::deque<int> mydeque;
// 在队尾插入元素
mydeque.push_back(10);
mydeque.push_back(20);
mydeque.push_back(30);
// 在队首插入元素
mydeque.push_front(5);
std::cout << "Front element: " << mydeque.front() << std::endl;
std::cout << "Back element: " << mydeque.back() << std::endl;
// 在队首和队尾删除元素
mydeque.pop_front();
mydeque.pop_back();
std::cout << "Size of deque: " << mydeque.size() << std::endl;
// 遍历 deque
for (const auto& element : mydeque) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
结果
Front element: 5
Back element: 30
Size of deque: 2
10 20
在这个示例中,我们创建了一个 std::deque
,在队尾和队首插入元素,访问队首和队尾元素,删除队首和队尾元素,并遍历整个 deque
。
总之,std::deque 是一个灵活的容器,适用于需要在两端进行高效插入和删除操作的场景。它是 STL 提供的一个重要的容器之一,用于满足不同的需求。
set
std::set
是一个关联容器,用于存储一组唯一的元素,这些元素按照特定的顺序自动排序。std::set
内部的元素是按照红黑树(一种平衡二叉搜索树)的数据结构来组织的,这使得插入、删除和查找元素的操作都具有较快的平均时间复杂度。
重要特性和用法:
-
唯一元素:
std::set
中的元素是唯一的,不允许重复的元素存在。插入重复元素将会被忽略。 -
自动排序:
std::set
中的元素按照严格弱序排列,即默认升序排序。可以通过提供自定义的比较函数来改变排序规则。 -
查找操作: 使用
find()
方法可以在集合中查找指定的元素,返回一个迭代器指向该元素。如果元素不存在,迭代器将指向集合末尾。 -
插入操作: 使用
insert()
方法可以向集合中插入元素,插入操作会保持集合的有序性。 -
删除操作: 使用
erase()
方法可以从集合中删除指定的元素,也可以通过迭代器范围删除一组元素。 -
遍历集合: 可以使用迭代器遍历
std::set
中的元素,这些元素将按照升序顺序输出。
示例代码
#include <iostream>
#include <set>
int main() {
std::set<int> myset;
// 插入元素
myset.insert(30);
myset.insert(10);
myset.insert(20);
// 查找元素
auto it = myset.find(10);
if (it != myset.end()) {
std::cout << "Element found: " << *it << std::endl;
} else {
std::cout << "Element not found" << std::endl;
}
// 删除元素
myset.erase(20);
// 遍历集合
for (const auto& element : myset) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
结果
Element found: 10
10 30
在这个示例中,我们创建了一个 std::set,插入了一些元素,查找元素,删除元素,并遍历整个集合。
std::set
是一个有序的、唯一元素的集合,适用于需要维护有序不重复数据的场景。
map
std::map
是一个关联容器,用于存储一组键值对(key-value pairs)。每个键都是唯一的,且按照键的严格弱序进行自动排序。std::map
内部使用红黑树(一种平衡二叉搜索树)数据结构来实现,这使得插入、删除和查找键值对的操作都具有较快的平均时间复杂度。
重要特性和用法
-
键的唯一性:
std::map
中的键是唯一的,不允许重复的键存在。插入具有相同键的元素将会被忽略。 -
自动排序:
std::map
中的键按照严格弱序排列,默认升序排序。可以通过提供自定义的比较函数来改变排序规则。 -
查找操作: 使用
find()
方法可以在映射中根据键查找对应的值,返回一个迭代器指向该键值对。如果键不存在,迭代器将指向映射的末尾。 -
插入操作: 使用
insert()
方法可以向映射中插入键值对,插入操作会保持映射的有序性。 -
删除操作: 使用
erase()
方法可以从映射中根据键删除对应的键值对。 -
遍历映射: 可以使用迭代器遍历
std::map
中的键值对,这些键值对将按照键的顺序输出。
示例代码
#include <iostream>
#include <map>
int main() {
std::map<int, std::string> mymap;
// 插入键值对
mymap.insert(std::make_pair(3, "Alice"));
mymap.insert(std::make_pair(1, "Bob"));
mymap.insert(std::make_pair(2, "Charlie"));
// 查找值
auto it = mymap.find(2);
if (it != mymap.end()) {
std::cout << "Value found: " << it->second << std::endl;
} else {
std::cout << "Value not found" << std::endl;
}
// 删除键值对
mymap.erase(1);
// 遍历映射
for (const auto& kvp : mymap) {
std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
}
return 0;
}
Value found: Charlie
Key: 2, Value: Charlie
Key: 3, Value: Alice
在这个示例中,我们创建了一个 std::map
,插入了一些键值对,查找值,删除键值对,并遍历整个映射。
std::map
是一个有序的键值对集合,适用于需要维护有序键值数据的场景。
multiset
std::multiset
是一个关联容器,类似于 std::set
,但允许存储多个相同的键(允许重复的键)。std::multiset
中的元素按照键的严格弱序自动排序,并且可以包含相同的键。std::multiset
也使用红黑树(一种平衡二叉搜索树)数据结构来实现,这使得插入、删除和查找元素的操作都具有较快的平均时间复杂度。
重要特性和用法
-
允许重复键: 与
std::set
不同,std::multiset
中的键可以重复。多个相同的键都会被存储在容器中。 -
自动排序:
std::multiset
中的键按照严格弱序排列,默认升序排序。可以通过提供自定义的比较函数来改变排序规则。 -
查找操作: 使用
find()
方法可以在多重集合中查找指定的键,返回一个迭代器指向第一个匹配的键。如果键不存在,迭代器将指向多重集合的末尾。 -
插入操作: 使用
insert()
方法可以向多重集合中插入键,插入操作会保持多重集合的有序性。 -
删除操作: 使用
erase()
方法可以从多重集合中删除指定的键,也可以通过迭代器范围删除一组键。 -
遍历多重集合: 可以使用迭代器遍历
std::multiset
中的键。
示例代码
#include <iostream>
#include <set>
int main() {
std::multiset<int> mymultiset;
// 插入键
mymultiset.insert(30);
mymultiset.insert(10);
mymultiset.insert(20);
mymultiset.insert(10); // 允许重复键
// 查找键
auto it = mymultiset.find(10);
if (it != mymultiset.end()) {
std::cout << "Key found: " << *it << std::endl;
} else {
std::cout << "Key not found" << std::endl;
}
// 删除键
mymultiset.erase(10);
// 遍历多重集合
for (const auto& key : mymultiset) {
std::cout << key << " ";
}
std::cout << std::endl;
return 0;
}
Key found: 10
20 30
在这个示例中,我们创建了一个 std::multiset
,插入了一些键,查找键,删除键,并遍历整个多重集合。
std::multiset
是一个允许重复键的有序集合,适用于需要维护有序且允许重复元素的场景。
unordered_set
std::unordered_set
是一个关联容器,用于存储一组唯一的元素,这些元素无序存储。与 std::set
和 std::multiset
不同,std::unordered_set
不会对元素进行排序,而是使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。
重要特性和用法
-
唯一元素:
std::unordered_set
中的元素是唯一的,不允许重复的元素存在。插入重复元素将会被忽略。 -
无序存储:
std::unordered_set
中的元素不会按照特定的顺序存储,而是基于哈希表的散列存储。 -
插入操作: 使用
insert()
方法可以向无序集合中插入元素,插入操作的时间复杂度通常是常数时间。 -
删除操作: 使用
erase()
方法可以从无序集合中删除指定的元素。 -
查找操作: 使用
find()
方法可以在无序集合中查找指定的元素,返回一个迭代器指向该元素。如果元素不存在,迭代器将指向集合的末尾。 -
遍历集合: 可以使用迭代器遍历
std::unordered_set
中的元素。
示例代码
#include <iostream>
#include <unordered_set>
int main() {
std::unordered_set<int> myunorderedset;
// 插入元素
myunorderedset.insert(30);
myunorderedset.insert(10);
myunorderedset.insert(20);
myunorderedset.insert(10); // 插入重复元素
// 查找元素
auto it = myunorderedset.find(10);
if (it != myunorderedset.end()) {
std::cout << "Element found: " << *it << std::endl;
} else {
std::cout << "Element not found" << std::endl;
}
// 删除元素
myunorderedset.erase(20);
// 遍历集合
for (const auto& element : myunorderedset) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
Element found: 10
30 10
在这个示例中,我们创建了一个 std::unordered_set
,插入了一些元素,查找元素,删除元素,并遍历整个集合。
std::unordered_set
是一个无序的、唯一元素的集合,适用于需要高效插入、删除和查找操作的场景。
unordered_map
介绍
std::unordered_map 是一个关联容器,用于存储一组键值对(key-value pairs)。与 std::map 不同,std::unordered_map 中的元素无序存储,并且使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。
重要特性和用法
-
键的唯一性:
std::unordered_map
中的键是唯一的,不允许重复的键存在。插入具有相同键的键值对将会被忽略。 -
无序存储:
std::unordered_map
中的键值对不会按照特定的顺序存储,而是基于哈希表的散列存储。 -
插入操作: 使用
insert()
方法可以向无序映射中插入键值对,插入操作的时间复杂度通常是常数时间。 -
删除操作: 使用
erase()
方法可以从无序映射中根据键删除对应的键值对。 -
查找操作: 使用
find()
方法可以在无序映射中根据键查找对应的值,返回一个迭代器指向该键值对。如果键不存在,迭代器将指向无序映射的末尾。 -
遍历映射: 可以使用迭代器遍历
std::unordered_map
中的键值对。
示例代码
#include <iostream>
#include <unordered_map>
int main() {
std::unordered_map<std::string, int> myunorderedmap;
// 插入键值对
myunorderedmap.insert(std::make_pair("Alice", 30));
myunorderedmap.insert(std::make_pair("Bob", 25));
myunorderedmap.insert(std::make_pair("Charlie", 28));
myunorderedmap.insert(std::make_pair("Alice", 22)); // 插入重复键
// 查找值
auto it = myunorderedmap.find("Bob");
if (it != myunorderedmap.end()) {
std::cout << "Value found: " << it->second << std::endl;
} else {
std::cout << "Value not found" << std::endl;
}
// 删除键值对
myunorderedmap.erase("Charlie");
// 遍历映射
for (const auto& kvp : myunorderedmap) {
std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
}
return 0;
}
Value found: 25
Key: Alice, Value: 30
Key: Bob, Value: 25
在这个示例中,我们创建了一个 std::unordered_map
,插入了一些键值对,查找值,删除键值对,并遍历整个映射。
std::unordered_map
是一个无序的键值对集合,适用于需要高效插入、删除和查找操作的场景。
unordered_multiset
介绍
std::unordered_multiset
是一个关联容器,类似于 std::unordered_set
,但允许存储多个相同的键(允许重复的键)。std::unordered_multiset
中的元素无序存储,并且使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。
重要特性和用法
-
允许重复键: 与
std::unordered_set
不同,std::unordered_multiset
中的键可以重复。多个相同的键都会被存储在容器中。 -
无序存储:
std::unordered_multiset
中的元素不会按照特定的顺序存储,而是基于哈希表的散列存储。 -
插入操作: 使用
insert()
方法可以向无序多重集合中插入元素,插入操作的时间复杂度通常是常数时间。 -
删除操作: 使用
erase()
方法可以从无序多重集合中根据元素删除对应的元素。 -
查找操作: 使用
find()
方法可以在无序多重集合中查找指定的元素,返回一个迭代器指向该元素。如果元素不存在,迭代器将指向集合的末尾。 -
遍历集合: 可以使用迭代器遍历
std::unordered_multiset
中的元素。
示例代码
#include <iostream>
#include <unordered_set>
int main() {
std::unordered_multiset<int> myunorderedmultiset;
// 插入元素
myunorderedmultiset.insert(30);
myunorderedmultiset.insert(10);
myunorderedmultiset.insert(20);
myunorderedmultiset.insert(10); // 允许重复元素
// 查找元素
auto it = myunorderedmultiset.find(10);
if (it != myunorderedmultiset.end()) {
std::cout << "Element found: " << *it << std::endl;
} else {
std::cout << "Element not found" << std::endl;
}
// 删除元素
myunorderedmultiset.erase(20);
// 遍历集合
for (const auto& element : myunorderedmultiset) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
Element found: 10
10 10 30
在这个示例中,我们创建了一个 std::unordered_multiset
,插入了一些元素,查找元素,删除元素,并遍历整个集合。
std::unordered_multiset
是一个无序的、允许重复元素的集合,适用于需要高效插入、删除和查找操作的场景。
unordered_multimap
介绍
std::unordered_multimap
是一个关联容器,类似于 std::unordered_map
,但允许存储多个相同的键(允许重复的键)。std::unordered_multimap
中的元素无序存储,并且使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。
重要特性和用法
-
允许重复键: 与
std::unordered_map
不同,std::unordered_multimap
中的键可以重复。多个相同的键都会被存储在容器中。 -
无序存储:
std::unordered_multimap
中的键值对不会按照特定的顺序存储,而是基于哈希表的散列存储。 -
插入操作: 使用
insert()
方法可以向无序多重映射中插入键值对,插入操作的时间复杂度通常是常数时间。 -
删除操作: 使用
erase()
方法可以从无序多重映射中根据键删除对应的键值对。 -
查找操作: 使用
find()
方法可以在无序多重映射中根据键查找对应的值,返回一个迭代器指向该键值对。如果键不存在,迭代器将指向映射的末尾。 -
遍历映射: 可以使用迭代器遍历
std::unordered_multimap
中的键值对。
示例代码
#include <iostream>
#include <unordered_map>
int main() {
std::unordered_multimap<std::string, int> myunorderedmultimap;
// 插入键值对
myunorderedmultimap.insert(std::make_pair("Alice", 30));
myunorderedmultimap.insert(std::make_pair("Bob", 25));
myunorderedmultimap.insert(std::make_pair("Alice", 22)); // 允许重复键
// 查找值
auto range = myunorderedmultimap.equal_range("Alice");
for (auto it = range.first; it != range.second; ++it) {
std::cout << "Value: " << it->second << std::endl;
}
// 删除键值对
myunorderedmultimap.erase("Bob");
// 遍历映射
for (const auto& kvp : myunorderedmultimap) {
std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
}
return 0;
}
Value: 22
Value: 30
Key: Alice, Value: 22
Key: Alice, Value: 30
在这个示例中,我们创建了一个 std::unordered_multimap
,插入了一些键值对,查找值,删除键值对,并遍历整个映射。
std::unordered_multimap
是一个无序的、允许重复键的键值对集合,适用于需要高效插入、删除和查找操作的场景。
bitset
介绍
std::bitset
是一个模板类,用于表示一个固定长度的二进制位序列,即一串由 0 和 1 组成的位值。std::bitset
提供了一系列操作来进行位操作、位检查和位设置等操作,以及一些与位相关的操作符重载。
重要特性和用法
-
固定长度: std::bitset 是一个固定长度的位序列,长度在编译时就已经确定。长度由模板参数指定。
-
位操作: std::bitset 支持位操作,如按位与(&)、按位或(|)、按位异或(^)、按位取反(~)等。
-
位设置和检查: 可以使用 set() 方法将特定位置的位设置为 1,使用 reset() 方法将特定位置的位设置为 0,使用 test() 方法检查特定位置的位是否为 1。
-
位翻转: 使用 flip() 方法可以将所有位的值翻转,1 变为 0,0 变为 1。
-
位计数: 使用 count() 方法可以计算位值为 1 的位的数量。
-
操作符重载: std::bitset 支持多种位相关的操作符重载,使得位操作更方便。
示例代码
#include <iostream>
#include <bitset>
int main() {
std::bitset<8> bits; // 创建一个长度为 8 的位序列
bits.set(1); // 将第 1 位设置为 1
bits.set(3, true); // 将第 3 位设置为 1,与 set(3) 等价
bits.set(5, false); // 将第 5 位设置为 0
std::cout << "Bits: " << bits << std::endl;
if (bits.test(3)) {
std::cout << "Bit at position 3 is set." << std::endl;
}
bits.flip(); // 翻转所有位的值
std::cout << "Flipped bits: " << bits << std::endl;
std::cout << "Number of set bits: " << bits.count() << std::endl;
return 0;
}
Bits: 00001010
Bit at position 3 is set.
Flipped bits: 11110101
Number of set bits: 6
在这个示例中,我们创建了一个长度为 8 的 std::bitset
,设置了其中的一些位,检查了位的状态,翻转了位的值,并计算了位值为 1 的位的数量。
std::bitset
在处理位运算和位操作时非常有用,可以用于位字段操作、位掩码、压缩标志等场景。
总汇
我们不需要讲这些容器全部记住,在做算法题的过程中如果忘记了就上网搜,刷题刷多了自然就记住了,如果没记住说明用的次数太少。当然,使用stl中的这些数据结构可能会有些慢,我们也可以用数组模拟,像 链表、栈、队列、哈希表 等数据结构都可以用数组模拟,还有一些数据结构 stl 中并没有,例如并查集,Trie树等,因为这些数据结构的使用场景比较复杂。