一、Map容器简介
C++中的Map容器是一种关联式容器,它将 key-value 映射对存储在内部树结构中,允许通过键访问元素,而键可以是任意可比较类型。使用Map容器可以轻松实现一些搜索、排序、计数等功能,也可以快速实现字典/哈希表的功能。Map的底层实现是红黑树,所以其时间复杂度一般为log(n)。
下面是一个简单的使用Map容器的示例:
#include <iostream>
#include <map>
using namespace std;
int main() {
// 声明并初始化一个Map容器
map<string, int> myMap = {{"apple", 1}, {"orange", 2}, {"banana", 3}};
// 输出Map容器中所有映射对
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
cout << it->first << " -> " << it->second << endl;
}
// 查找并输出Map容器中指定键对应的值
string key = "apple";
cout << "The value of " << key << " is: " << myMap[key] << endl;
return 0;
}
二、提高Map容器的性能
1. 使用emplace()代替insert()
在向Map容器中插入新的元素时,通常会使用insert()函数实现。但是,如果使用insert()函数插入新的元素,就意味着需要先构造一个pair对象,再将其作为参数传入insert()函数中,这样会造成额外的开销。而emplace()函数就是为了解决这个问题而设计的。使用emplace()函数插入新元素时,就可以直接向emplace()函数中传入对应的键和值,实现更加高效的插入操作。
下面是一个使用emplace()函数的示例:
#include <iostream>
#include <map>
using namespace std;
int main() {
// 声明并初始化一个Map容器
map<string, int> myMap = {{"apple", 1}, {"orange", 2}, {"banana", 3}};
// 使用emplace()函数插入一个新元素
myMap.emplace("peach", 4);
// 输出Map容器中所有映射对
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
cout << it->first << " -> " << it->second << endl;
}
return 0;
}
2. 使用lower_bound()和upper_bound()代替find()
在Map容器中查找指定键值对应的值时,通常使用find()函数实现。但是,由于Map容器中元素是有序的,所以可以使用lower_bound()和upper_bound()函数代替find()函数,从而实现更高效的查找操作。
lower_bound()函数可以查找第一个大于等于指定键值的元素的迭代器,而upper_bound()函数则可以查找第一个大于指定键值的元素的迭代器。通过这两个函数的结合使用,就可以快速的实现在Map容器中查找指定键值的操作。
下面是一个使用lower_bound()和upper_bound()函数的示例:
#include <iostream>
#include <map>
using namespace std;
int main() {
// 声明并初始化一个Map容器
map<string, int> myMap = {{"apple", 1}, {"orange", 2}, {"banana", 3}};
// 使用lower_bound()函数查找第一个大于等于指定键值的元素
auto it_lower = myMap.lower_bound("mango");
// 使用upper_bound()函数查找第一个大于指定键值的元素
auto it_upper = myMap.upper_bound("mango");
// 输出查找到的元素的迭代器
cout << "The lower bound is: " << it_lower->first << " -> " << it_lower->second << endl;
cout << "The upper bound is: " << it_upper->first << " -> " << it_upper->second << endl;
return 0;
}
3. 避免频繁的插入和删除操作
Map容器的底层实现是红黑树,其插入和删除操作需要重新构建树结构,开销比较大。在实际使用中,应该尽量减少频繁的插入和删除操作,以提高Map容器的性能。
下面是一个插入元素较多、删除元素较多的示例程序,可以看到其性能比较低:
#include <iostream>
#include <map>
#include <ctime>
using namespace std;
int main() {
map<int, int> myMap;
time_t start = time(nullptr);
// 插入1~1000000个元素
for (int i = 1; i <= 1000000; ++i) {
myMap[i] = i;
}
cout << "Time elapsed for inserting 1000000 elements: " << time(nullptr) - start << endl;
start = time(nullptr);
// 删除1~1000000个元素
for (int i = 1; i <= 1000000; ++i) {
myMap.erase(i);
}
cout << "Time elapsed for erasing 1000000 elements: " << time(nullptr) - start << endl;
return 0;
}
三、内存管理
Map容器是一种占用内存较大的容器,尤其是在元素数量较大、目标机是否足够内存的情况下,需要高效利用内存。
1. 定制Map容器的比较函数
Map容器的键类型必须支持比较操作,否则会出现编译错误。如果Map容器的键类型是自定义类型,可以通过定制比较函数的方式,实现对Map容器的排序或者改变Map容器元素的比较方式,从而达到优化内存使用的效果。
下面是一个定义自定义类型的Map容器,并定制比较函数的示例:
#include <iostream>
#include <map>
using namespace std;
class MyType {
public:
int value;
MyType(int v) : value(v) {}
bool operator<(const MyType &other) const {
return this->value < other.value;
}
};
int main() {
// 声明并初始化一个Map容器,使用自定义类型作为键类型,并定制比较函数
map<MyType, int> myMap{{MyType(2), 10}, {MyType(1), 20}, {MyType(3), 30}};
// 输出Map容器中所有映射对
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
cout << it->first.value << " -> " << it->second << endl;
}
return 0;
}
2. 禁止Map容器的自动扩容
通过控制Map容器的默认扩容策略,可以有效地控制Map容器的内存使用。
Map容器默认的扩容策略是定期扩容,在容器元素数量增加到一定程度时,会自动对容器进行扩容,以增大容器的容量。这种自动扩容的策略会导致容器的内存占用一直处于相对较高的状态,对于内存资源宝贵的场景来说,可能会造成浪费。所以,在某些场景下,可以通过禁止Map容器的自动扩容来控制内存的使用。
下面是一个禁止Map容器自动扩容的示例程序:
#include <iostream>
#include <map>
using namespace std;
int main() {
// 声明并初始化一个Map容器,同时禁止该Map容器的自动扩容
map<int, int> myMap;
myMap.max_load_factor(1.0);
// 清空Map容器,保证容器内没有元素
myMap.clear();
// 插入1~1000000个元素
for (int i = 1; i <= 1000000; ++i) {
myMap[i] = i;
}
return 0;
}
3. 合并Map容器
在某些场景下,可能需要将多个Map容器合并成一个Map容器,这时可以使用Map容器的合并函数——merge(),将多个Map容器中的元素合并到一个Map容器中,从而减少内存的使用,避免多个Map容器的重复存储。
下面是一个合并Map容器的示例程序:
#include <iostream>
#include <map>
using namespace std;
int main() {
// 声明并初始化两个Map容器
map<int, int> myMap1 = {{1, 10}, {2, 20}, {3, 30}};
map<int, int> myMap2 = {{4, 40}, {5, 50}, {6, 60}};
// 使用merge()函数合并两个Map容器
myMap1.merge(myMap2);
// 输出合并后的Map容器中所有映射对
for (auto it = myMap1.begin(); it != myMap1.end(); ++it) {
cout << it->first << " -> " << it->second << endl;
}
return 0;
}
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/151188.html
微信扫一扫
支付宝扫一扫