C++ STL浅析
1、pair
(1)定义和结构
定义:在C++中,pair是一个模板类,用于表示一对值的组合。它位于<utility>
头文件中,pair类的定义如下:
-
有两个模板参数,T1和T2,分别表示第一个值和第二个值的类型。
-
有两个成员变量,first和second,分别表示第一个值和第二个值。
-
还有一些成员函数和特性例如默认构造函数、带参数的构造函致、比较运算符重载等。
结构:使用pair类,你可以方便地将两个值组合在一起,并进行传递一存储利操作。例如,可以将两个整数组合在一起作为函数的返
回值,或者将一对值存储在容器中。
下面是一些使用pair的示例:
以上代码创建了两个pair对象,分别包含不同类型的值。然后,通过访问first和second)成员变量,输出了这些值。
(2)嵌套
pair可以进行嵌套,也就是说可以将一个pair对象作为另一个pair对象的成员。通过嵌套pair,可以方便地组合多个值,并形成更复杂的数据结构。
例如,可以创建一个三维坐标系的点,其中第1个维度由一个整数表示,第2、3个维度由一个pair表示。
下面是一个示例代码,演示了如何嵌套使用pair:
在这个示例中,我们创建了三个pair对象:p1、p2和p3,
- p1是一个简单的pair,包含两个整数值。
- p2是一个嵌套的pair,其中第一个值是一个整数,第二个值是一个pair,其中包含两个整数值。
- p3是一个嵌套的pair,其中每个值都是一个pair,每个pair包含两个整数值。通过访问嵌套的pair对象的成员变量,我们可以获取到相应的值。
(3)自带排序规则
pair自带的排序规则是按照first
成员进行升序排序。如果first
成员相等,则按照second
成员进行升序排序。这意味着当你使用标准库中的排序算法(如std:sort
)对包含pair对象的容器进行排序时,会根据pair对象的first
成员进行排序。
下面是一个示例代码,演示了如何使用pair进行排序:
在这个示例中,我们创建了一个存储pair对象的向量vec,其中包含三个pair对象。然后,我们使用std:sort
函数对vec进行排序。由于pair对象的排序规则是按照first
成员进行升序排序,所以排序后的结果是:
最后,我们通过遍历vec并输出每个pair对象的成员,验证了排序结果。需要注意的是,如果你想按照其他排序规则对pair进行排序,可以自定义比较函数或使用lambda表达式来传递给排序算法。这样,你可以根据自己的需求定义排序规则。
(4)代码示例
2、vector
(1)定义和特性
定义:在C+中,vector是一个动态数组容器,可以存储一系列相同类型的元素它是标准库中定义的模板类。
结构:vector的定义和结构非常简单,它由以下几个重要的部分组成:模板类声明:vector是一个模板类,因此在使用之前需要包含头文件<vector>
.。声明一个vector对象的通用语法如下:std::vector<T> vec;
,这里的T是要存储在vector中的元素类型。
容器大小:vector是一个动态数组,可以根据需要自动调整大小。它会根据元素的数量动态分配内存空间。
元素访问:可以通过索引来访问vector中的元素。索引从0
开始,最后一个元素的索引是size()-1
。可以使用[]
运算符或at()
函数来访问元素。
元素添加和删除:可以使用push_back()
函数在vector的末尾添加元素,使用pop_back()
函数删除末尾的元素。还可以使用insert()
函数在指定位置插大元素,使用erase()
函数删除指定位置的元素
迭代器:vector提供了迭代器,可以用于遍历容器中的元素。可以使用begin(O函数获取指向第一个元素的迭代器,使用end()
函数获取指向最后一个元素之后位置的迭代器。
(2)常用函数
push_back()
将元素添加到vectorl的末尾:
void push_back(const T& value);
pop_back()
删除vector末尾的元素:
void pop_back();
PS:一定要保证vector非空!!!
begin()和end()
返回指向vector第一个元素和最后一个元素之后位置的迭代器:
vector<int> vec = {10, 20, 30};
for(auto it = vec.begin(); it != vec.end(); it ++) cout << *it << ' ';
cout << endl;
(3)排序去重
去重:要去除vector中的重复元素,可以使用unique()
函数。该函数位于头文件<algorithm>
中。
首先,需要对vector进行排序,以便相同的元素相邻。然后,unique()
函数将重复的元素移动到vector的末尾,并返回一个指向重复元素的迭代器。最后,可以使用erase()
函数将重复元素从vector中删除。
(4)代码示例
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> vec = {2, 1, 3, 2, 4, 1, 5, 4};
sort(vec.begin(), vec.end());
auto last = unique(vec.begin(), vec.end()); // last为最后一个不重复元素的索引
vec.erase(last, vec.end()); // 在last对应元素之后的元素都是跟前边元素重复的,全部删除
for(auto it : vec) cout << it << ' '; // 此处it类型为int,不是迭代器,没有 *
cout << endl;
return 0;
}
这样,vector中的重复元素被去除,只保留了不重复的元素。
3、list
(1)定义和结构
list的使用频率不高,在做题时极少遇到需要使用Iist的情景。list是一种双向链表容器,它是标准模板库(STL)提供的一种序列容器。Iist容器以节点(node)的形式存储元素,并使用指)将这些节点链接在一起,形成一个链表结构。
template <class(T), class Allocator = std:allocator<T>>
class list;
list容器模板接受两个参数:
1、T:指定容器中存储的元素类型。
2、Allocator(可选):指定用于分配内存的分配器类型,默认为std:allocator
list容器的特点包括:
- 双向性:每个节点都包含指向前一个节点和后一个节点的指针,因此可以在常数时间内在链表中的任意位置进行插入、删除和访问操作。
- 动态大小:链表的大小可以根据需要动态打展或收缩,不需要预先指定容器的大小。
- 不连续存储:链表中的节点可以在内存中的任意位置分布,不要求连续存储,因此插人和删除操作不会导致元素的移动。
list容器提供了一系列成员函数和迭代器来操作和访问链表中的元素,包括插入删除、访问、反转等操作。可以使用迭代器来遍历链表中的元素。
以下为一个示例,展示如何使用list容器:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> myList;
myList.push_back(1); // 在双向链表尾部插入元素
myList.push_back(2);
myList.push_back(3);
myList.push_front(0); // 在双向链表头部插入元素
for(int num : myList) cout << num << ' ';
cout << endl;
return 0;
}
需要注意的是,由于Iist是双向链表,因此插入和删除操作的时间复杂度是常量时间O(1)
,但访问和查找操作的时间复杂度是线性时间O(n)
,其中n是链表的大小。因此,如果需要频繁进行随机访问操作,可能更适合使用支持随机访问的容器,如vector或deque。
(2)常用函数
list容器提供了多个常用的成员函数来操作和访问链表中的元素。
以下是一些常用的list函数的解释:
函数 | 描述 |
---|---|
push back() | 将元素插入到链表的末尾 |
push front() | 将元素插入到链表的开头 |
pop_back() | 移除链表末尾的元素 |
pop_front() | 移除链表开头的元素 |
size() | 返回链表中元素的个数 |
empty() | 检查链表是否为空 |
clear() | 清空链表中的所有元素 |
front() | 返回链表中第一个元素的引用 |
back() | 返回链表中最后一个元素的引用 |
begin() | 返回指向链表第一个元素的迭代器 |
end() | 返回指向链表末尾的下一个位置的迭代器 |
insert() | 在指定位置之前插人一个或多个元素 |
erase() | 从链表中移除指定位置的一个或多个元素 |
(3)代码示例
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
list<int> myList;
for(int i = 1; i <= 5; i ++) myList.push_back(i);
for(const auto &i : myList) cout << i << ' ';
cout << endl;
reverse(myList.begin(), myList.end());
for(const auto &i : myList) cout << i << ' ';
cout << endl;
myList.insert(++ myList.begin(), 0);
for(const auto &i : myList) cout << i << ' ';
cout << endl;
myList.erase(++ ++ myList.begin(), -- myList.end());
cout << "链表大小为:" << myList.size() << endl;
for(const auto &i : myList) cout << i << ' ';
cout << endl;
return 0;
}
4、stack
(1)定义和结构
stack是一种后进先出(LIFO)的数据结构,使用前需要包含头文件。
stack提供了一组函薮来操作和访问元素,但它的功能相对较简单。
stack的定义和结构如下(仅作了解即可)。
template <class T, class Container = deque<T>>
class stack;
(2)常用函数
函数 | 描述 | 时间复杂度 |
---|---|---|
push(x) | 在栈顶插入元素x | O(1) |
pop() | 弹出栈顶元素 | O(1) |
top() | 返回栈顶元素 | O(1) |
empty() | 检查栈是否为空 | O(1) |
size() | 返回栈中元素的个数 | O(1) |
PS:如果将一个数组的元素依次放人栈,再依次取出,则可以将数组翻转。
(3)代码示例
#include <iostream>
#include <stack>
using namespace std;
int main()
{
stack<int> myStack;
// 向栈中插入元素
myStack.push(10);
myStack.push(20);
myStack.push(30);
myStack.push(40);
// 获取栈顶元素
cout << "栈顶元素:" << myStack.top() << endl;
// 弹出栈顶元素
myStack.pop();
// 再次获取元素
cout << "弹出一个元素后的栈顶元素:" << myStack.top() << endl;
// 检查是否为空
if(myStack.empty()) cout << "栈为空" << endl;
else cout << "栈不为空" << endl;
cout << "栈的大小:" << myStack.size() << endl;
return 0;
}
5、queue
(1)定义和结构
queue是一种先进先出的数据结构,提供了一组函数来操作和访问元素,但它的功j能相对较简单。
queue的定义和结构如下:
template <class T, class Container = deque<T>>
class queue;
- T:表示存储在queue中的元素的类型。
- Container:表示底层容器的类型,默认为deque。也可以使用其他容器类型,如list。
queue的内部实现使用了底层容器来存储元素,并且只能通过特定的函数来访问和操作元素。
(2)常用函数
函数 | 描述 | 时间复杂度 |
---|---|---|
push(x) | 在队尾插入元素x | O(1) |
pop() | 弹出队首元素 | O(1) |
front() | 返回队首元素 | O(1) |
back() | 返回队尾元素 | O(1) |
empty() | 检查队列是否为空 | O(1) |
size() | 返回队列中元素的个数 | O(1) |
(3)priority_queue
priority_queue与普通队列不同,priority_queue中的元素是按照一定的优先级进行排序的。
默认情况下,priority_queue按照元素的值从大到小进行排序,即最大元素位于队列的前面。
priority_queuel的定义和结构如下(仅做了解即可):
template <class T, class Container = vector<T>,
class Compare = less <typename, Container :: value_type>>
class priority_queue;
-
T:表示存储在priority.-queue中的元素的类型。
-
Container:表示底层容器的类型,默认为vector。也可以使用其他容器类型,如deque。
-
Compare:表示元素之间的比较函数对象的类型,默认为less,即按照元素的值进行比较。
priority_queue的内部实现使用了底层容器来存储元素,并且只能通过特定的函数来访问和操作元系。
常用函数
函数 | 描述 | 时间复杂度 |
---|---|---|
push(x) | 将元素× 插入到优先队列中 | O(logN) |
pop() | 弹出优先队列中的顶部元素 | O(logN) |
top() | 返回优先队列中的顶部元素 | O(1) |
empty() | 检查优先队列是香为空 | O(1) |
size() | 返回优先队列中元素的个数 | O(1) |
优先队列是一个十分重要的数据结构,考察频率极高!!!
修改比较函数的方法
#include <iostream>
#include <queue>
using namespace std;
struct
{
bool operator()(int a, int b)
{
// 自定义的比较函数,按照逆序排列
return a > b;
}
};
int main()
{
priority_queue<int, vector<int>, Compare> pq;
......
return 0;
}
(4)deque
deque(双端队列)是一种容器,它允许在两端进行高效的插入和删除操作。deque是由一系列连续的存储块(缓冲区)组成的,每个存
储块都存储了多个元素。这使得deque能够在两端进行快速的插入和删除操作,而不需要移动其他元素。
deque的定义和结构如下(仅做了解即可):
template <class T, class Allocator = allocator<T>>
class deque;
- T:表示存储在dequer中的元素的类型
- Allocator:表示用于分配内存的分配器类型,默认为allocator。deque的内部实现使用了一系列的存储块(缓冲区),每个存储块存储了多个元素,并且通过指针进行连接这种设计使得在两端进行插入和删除操作的时间复杂度为常数时间,即O(1)
后续的“单调队列”将使用双端队列来实现,单纯考察双端队列的并不常见。
常用函数
函数 | 描述 | 时间复杂度 |
---|---|---|
push_back(x) | 在尾部插入元素x | 平摊O(1) |
push_front(x) | 在头部插入元素x | 平摊O(1) |
pop_back() | 弹出尾部元素 | 平摊O(1) |
pop_front() | 弹出头部元素 | 平摊O(1) |
front() | 返回头部元素 | O(1) |
back() | 返回尾部元素 | O(1) |
empty() | 检查deque是否为空 | O(1) |
size() | 返回deque中元素的个数 | O(1) |
clear() | 清空deque中的所有元素 | O(1) |
6、set
(1)定义和结构
定义:set是一种容器,用于存储一组唯一的元素,并按照一定的排序规则进行排序。set中的元素是按照升序排序的,默认情况下,它使用元素的比较运算符(<)来进行排序。
set的定义和结构如下:
template <class Key, class Compare = less <Key>,
class Allocator = allocator<Key>>
class set;
- Key:表示存储在set中的元素的类型。
- Compare:表示元素之间的比较函数对象的类型,默认为less,即按照元素的值进行比较。
- Allocator:表示用于分配内存的分配器类型,默认为allocator。
set的内部实现使用了红黑树(一种自平衡的二叉搜索树)来存储元素,并保持元素的有序性。
这使得在set中插人、删除和查找元素的时间复杂度都是对数时间,即O(log n)。
set中的元素是唯一的,即不允许重复的元素存在。当插入一个重复的元素时,set会自动忽略该元素。
(2)常用函数
函数 | 描述 | 平均时间复杂度 | 最坏时间复杂度 |
---|---|---|---|
insert(x) | 向集合中插入元素x | O(logN) | O(logN) |
erase(x) | 从集合中移除元素x | O(logN) | O(logN) |
find(x) | 查找集合中的元素x | O(logN) | O(logN) |
lower_bound(x) | 返回一个不小于给定值x 的迭代器 | O(logN) | O(logN) |
upper_bound(x) | 返回第一个大于给定值x 的迭代器 | O(logN) | O(logN) |
equal_range(x) | 返回一个范围,其中包含所有给定值x 的元素 | O(logN) | O(logN) |
size() | 返回集合中元素的数量 | O(1) | O(1) |
empty() | 检查集合是否为空 | O(1) | O(1) |
clear() | 清空集合 | O(1) | O(1) |
begin() | 返回指向集合起始位置的迭代器 | O(1) | O(1) |
end() | 返回指向集合末尾的迭代器 | O(1) | O(1) |
rbegin() | 返回指向集合末尾位置的逆向迭代器 | O(1) | O(1) |
rend() | 返回指向集合起始位置的逆向迭代器 | O(1) | O(1) |
swap() | 交换两个集合 | O(1) | O(1) |
(3)代码示例
修改比较方法前:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int, greater<int>> mySet;
mySet.insert(25);
mySet.insert(17);
mySet.insert(39);
mySet.insert(42);
for(const auto& elem : mySet) cout << elem << ' ';
cout << endl;
return 0;
}
修改比较方法后:
#include <iostream>
#include <set>
using namespace std;
struct MyCompare
{
bool operator()(const int& a, const int& b) const
{
// 自定义比较逻辑
return a > b; // 改为逆序
}
};
int main()
{
set<int, MyCompare> mySet; // MyCompare为仿函数
mySet.insert(25);
mySet.insert(17);
mySet.insert(39);
mySet.insert(42);
for(const auto& elem : mySet) cout << elem << ' ';
cout << endl;
return 0;
}
(4)multiset
定义和结构
定义:multiset是一种容器,它与set类似,用于存储一组元素,并按照一定的排序规则进行排序。不同之处在于,multiset容器允许存储重复的元素。
multiset的定义和结构与set类似,如下所示:
template <class Key, class Compare = less<Key>,
class Allocator = allocator<Key>>
class multiset;
- Key:表示存储在multiset中的元素的类型。
- Compare:表示元素之间的比较函数对象的类型,默认为less,即按照元素的值进行比较。
- Allocator:表示用于分配内存的分配器类型,默认为allocator。
multiset的内部实现也使用红黑树来存储元素,并保持元素的有序性。与set不同的是,multiset中的元素可以重复出现。
常用函数
函数 | 描述 | 平均时间复杂度 | 最坏时间复杂度 |
---|---|---|---|
insert(x) | 向多重集合中插入元素x | O(logN) | O(logN) |
erase(x) | 从多重集合中移除元素x | O(logN) | O(logN) |
find(x) | 查找多重集合中的元素x | O(logN) | O(logN) |
lower_bound(x) | 返回一个不小于给定值x 的迭代器 | O(logN) | O(logN) |
upper_bound(x) | 返回第一个大于给定值x 的迭代器 | O(logN) | O(logN) |
equal_range(x) | 返回一个范围,其中包含所有给定值x 的元素 | O(logN) | O(logN) |
size() | 返回多重集合中元素的数量 | O(1) | O(1) |
empty() | 检查多重集合是否为空 | O(1) | O(1) |
clear() | 清空多重集合 | O(1) | O(1) |
begin() | 返回指向多重集合起始位置的迭代器 | O(1) | O(1) |
end() | 返回指向多重集合末尾的迭代器 | O(1) | O(1) |
rbegin() | 返回指向多重集合末尾位置的逆向迭代器 | O(1) | O(1) |
rend() | 返回指向多重集合起始位置的逆向迭代器 | O(1) | O(1) |
swap( , ) | 交换两个多重集合 | O(1) | O(1) |
PS:观察上表,其实multiset和set的函数是一样的。
(5)unordered_set
定义和结构
unordered_set是一种容器,用于存储一组唯一的元素,并且没有特定的顺序。unordered_set容器使用哈希表来实现
元素的存储和访问,因此元素的插入、删除和查找的时间厦杂度都是常数时间,即O(1)。
unordered._set的定义和结构如下:
template <class Key,class Hash hash<Key>,
class KeyEqual equal_to<Key>,
class Allocator allocator<Key>>
class unordered_set;
- Key:表示存储在unordered_set中的元素的类型
- Hash:表示用于计算元素哈希值的哈希函数对象的类型,默认为hash,使用Key类型的默认哈希函数。
- KeyEqual:表示用于比较元素是否相等的函数对象的类型,默认为equal_to,使用Key类型的默认相等比较函数。
- Allocator:表示用于分配内存的分配器类型,默认为allocator。
unordered_set中的元素是唯一的,即不允许重复的元素存在。当插入一个重复的元素时,unordered_.set会自动忽略该元素。
函数 | 描述 | 平均时间复杂度 | 最坏时间复杂度 |
---|---|---|---|
insert(x) | 向无序集合中插入元素x | O(1) | O(n) |
erase(x) | 从无序集合中移除元素x | O(1) | O(n) |
find(x) | 查找无序集合中的元素x | O(1) | O(n) |
count(x) | 返回元素x 在集合中的出现次数 | O(1) | O(n) |
size() | 返回无序集合中元素的数量 | O(1) | O(1) |
这些时间复杂度是基于哈希函数的性能和哈希冲突的情况来计算的。平均情况下,unordered_set的插入、查找和移除操作都具有常数时间复杂度O(1)。然而,在最坏情况下,这些操作的时间复杂度可能为O(n),其中n是无序集合中的元素数量。最坏情况通常发生在哈希冲突较为严重的情况下,导致需要线性探测或链式解决冲突,从而影响性能。所以我们一般情况下不会使用unordered_set,而选择使用复杂度更稳定的set。
代码示例
set和unordered_set处理重复元素的对比:
set:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> mySet;
mySet.insert(5);
mySet.insert(2);
mySet.insert(8);
mySet.insert(2); // 重复元素
// 遍历集合
cout << "Set elements:";
for(const auto& elem : mySet) cout << elem << ' ';
cout << endl;
// 查找元素
int searchValue = 5;
auto it = mySet.find(searchValue);
if(it != mySet.end()) cout << searchValue << "found in the set." << endl;
else cout << searchValue << "not found in the set." << endl;
int removeValue = 2;
mySet.erase(removeValue);
// 再次遍历集合
cout << "Set elements after removal";
for(const auto& elem : mySet) cout << elem << ' ';
cout << endl;
// 清空集合
mySet.clear();
// 检查集合是否为空
if(mySet.empty()) cout << "Set is empty." << endl;
else cout << "Set is not empty." << endl;
return 0;
}
unordered_set:
#include <iostream>
#include <unordered_set>
using namespace std;
int main()
{
unordered_set<int> myUnorderedSet;
myUnorderedSet.insert(5);
myUnorderedSet.insert(2);
myUnorderedSet.insert(8);
myUnorderedSet.insert(2); // 重复元素
// 遍历集合
cout << "Unorderedset elements:";
for(const auto& elem : myUnorderedSet) cout << elem << ' ';
cout << endl;
// 查找元素
int searchValue = 5;
auto it = myUnorderedSet.find(searchValue);
if(it != myUnorderedSet.end()) cout << searchValue << "found in the Unorderedset." << endl;
else cout << searchValue << "not found in the Unorderedset." << endl;
int removeValue = 2;
myUnorderedSet.erase(removeValue);
// 再次遍历集合
cout << "Set elements after removal";
for(const auto& elem : myUnorderedSet) cout << elem << ' ';
cout << endl;
// 清空集合
myUnorderedSet.clear();
// 检查集合是否为空
if(myUnorderedSet.empty()) cout << "UnorderedSet is empty." << endl;
else cout << "UnorderedSet is not empty." << endl;
return 0;
}
7、map
(1)定义和结构
定义:
- map是一种关联容器,用于存储一组键值列(key-value pairs),其中每个键(key)都是唯一的。
- map容器根据键来自动进行排序,并且可以通过键快速查找对应的值。
- map容器使用红黑树(Red-Black Tree)数据结构来实现,具有较快的插入、删除和查找操作的时间复杂度O(logn).
map的结构如下:
template <class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key, T>>>
class map;
- Key:表示存储在map中的键(key)的类型。
- T:表示在储在map中的值(value)的类型。
- Compare:表示用于比较键的函数对象的类型,默认为less,使用键类型的默认比较函数。
- Allocator:表示用于分配内存的分配器类型,默认为allocator。
(2)常用函数
函数 | 描述 | 时间复杂度 |
---|---|---|
insert(x) | 插入元素x | O(log n) |
erase(x) | 删除元素x | O(log n) |
find(x) | 查找元素x | O(log n) |
count() | 统计元素个数 | O(log n) |
size() | 返回元素个数 | O(1) |
begin() | 返回指向容器起始位置的迭代器 | O(1) |
end() | 返回指向容器末尾位置的迭代器 | O(1) |
clear() | 清空容器 | O(n) |
empty() | 判断容器是否为空 | O(1) |
lower_bound() | 返回指向第一个不小于指定键的元素位置 | O(log n) |
upper_bound() | 返回指向第一个大于指定键的元素位置 | O(log n) |
(3)multimap
定义和结构
- multimap是一种关联容器,类似于map,但允许存储多个具有相同键的键值对
- multimap容器根据键来自动进行排序,并且可以通过键快速查找对应的值。
- multimap容器使用红黑树(Red-Black Tree)数据结构来实现,具有较快的插入、删除和查找操作的时间复杂度。
multimap的结构如下:
template <class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key, T>>>
class multimap;
- Key:表示存储在multimap中的键(key)的类型
- T:表示存储在multimap中的值(value)的类型
- Compare:表示用于比较键的函数对象的类型,默认为less,使用键类型的默认比较函数,
- Allocator:表示用于分配内存的分配器类型,默认为allocator
在实际做题过程中,multimap几乎用不到。
常用函数
函数 | 描述 | 时间复杂度 |
---|---|---|
insert(x) | 插入元素x | O(log n) |
erase(x) | 删除元素x | O(log n) |
find(x) | 查找元素x | O(log n) |
count() | 统计元素个数 | O(log n) |
size() | 返回元素个数 | O(1) |
begin() | 返回指向容器起始位置的迭代器 | O(1) |
end() | 返回指向容器末尾位置的迭代器 | O(1) |
clear() | 清空容器 | O(n) |
empty() | 判断容器是否为空 | O(1) |
(4)unordered_map
定义和结构
- unordered_map是一种关联容器,用于存储一组键值对(key-value pairs),其中每个键(key)都是唯一的。
- 与map和multimap不同,unordered_map不会根据键的顺序进行排序,而是使用哈希函数将键映射到存储桶中。这使得unordered_map具有更快的插入、删除和查找操作的时间复杂度,但不保证元素的顺序。
unordered_map的结构如下:
template <class Key,class T,class Hash hash<Key>,
class KeyEqual equal_to<Key>,
class Allocator allocator<pair<const Key,T>>>
class unordered_map;
- Key:表示存储在unordered_map中的键(key)的类型
- T:表示存储在unordered_map中的值(value)的类型。
- Hash:表示用于计算键的哈希值的函数对象的类型,默认为hash,使用键类型的默认哈希函数。
- KeyEqual:表示用于比较键的函数对象的类型,默认为equal_to,使用键类型的默认比较函数。
- Allocator:表示用于分配内存的分配器类型,默认为allocator。
常用函数
函数 | 描述 | 平均时间复杂度 | 最坏时间复杂度 |
---|---|---|---|
insert(x) | 插入元素x | O(1) | O(n) |
erase(x) | 删除元素x | O(1) | O(n) |
find(x) | 查找元素x | O(1) | O(n) |
count() | 统计元素个数 | O(1) | O(n) |
size() | 返回元素个数 | O(1) | O(1) |
clear() | 清空容器 | O(1) | O(n) |
empty() | 判断容器是否为空 | O(1) | O(1) |
(5)代码示例
map:
#include <iostream>
#include <map>
using namespace std;
int main()
{
// 创建并初始化map
map<int, string> myMap = {{1, "Apple"}, {2, "Banana"}, {3, "Orange"}};
// 插入元素
myMap.insert(make_pair(4, "Grapes"));
// 查找和访问元素
cout << "Value at key 2:" << myMap[2] << endl;
// 遍历并打印 map 中的元素
for(const auto& pair : myMap) cout << "Key:" << pair.first << ", Value:" << pair.second << endl;
// 删除元素
myMap.erase(3);
// 判断元素是否存在
if(myMap.count(3) == 0) cout << "Key 3 not found." << endl;
// 删除元素
myMap.erase(3);
// 判断元素是否存在
if(myMap.count(3) == 0) cout << "Key 3 not found." << endl;
// 清空 map
myMap.clear();
// 判断 map 是否为空
if(myMap.empty()) cout << "Map is empty." << endl;
return 0;
}
mutimap:
#include <iostream>
#include <map>
using namespace std;
int main()
{
// 创建并初始化map
multimap<int, string> myMultiMap = {{1, "Apple"}, {2, "Banana"}, {3, "Orange"}};
// 插入元素
myMultiMap.insert(make_pair(4, "Grapes"));
// 查找和访问元素
auto range = myMultiMap.equal_range(2);
for(auto it = range.first; it != range.second; it ++) cout << "Key:" << it->first << ", Value:" << it->second << endl;
// 遍历并打印 map 中的元素
for(const auto& pair : myMultiMap) cout << "Key:" << pair.first << ", Value:" << pair.second << endl;
// 删除元素
myMultiMap.erase(2);
// 判断元素是否存在
if(myMultiMap.count(2) == 0) cout << "Key 3 not found." << endl;
// 删除元素
myMultiMap.erase(2);
// 判断元素是否存在
if(myMultiMap.count(2) == 0) cout << "Key 3 not found." << endl;
// 清空 map
myMultiMap.clear();
// 判断 map 是否为空
if(myMultiMap.empty()) cout << "myMultiMap is empty." << endl;
return 0;
}
unordered_map:
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
// 创建并初始化map
unordered_map<string, int> myMap = {{"Apple", 3}, {"Banana", 5}, {"Orange", 2}};
// 插入元素
myMap.insert(make_pair("Grapes", 4));
// 查找和访问元素
cout << "Value for key 'Banana':" << myMap["Banana"] << endl;
// 遍历并打印 map 中的元素
for(const auto& pair : myMap) cout << "Key:" << pair.first << ", Value:" << pair.second << endl;
// 删除元素
myMap.erase("Orange");
// 判断元素是否存在
if(myMap.count("Orange") == 0) cout << "Key 3 not found." << endl;
// 删除元素
myMap.erase("Orange");
// 判断元素是否存在
if(myMap.count("Orange") == 0) cout << "Key 3 not found." << endl;
// 清空 map
myMap.clear();
// 判断 map 是否为空
if(myMap.empty()) cout << "Unordered_map is empty." << endl;
return 0;
}