map和set
关联式容器
前面了解过的vector,list,string等容器都是序列式容器,存储的都是元素本身,底层都是线性的数据结构。
而map和set存储的都是<key,value> 的键值对,在进行数据检索时效率更高
STL中对键值对的定义:
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
};
set
文档:https://legacy.cplusplus.com/reference/set/set/?kw=set
set介绍
- 查找:set的底层是红黑树,存储键值对,中序遍历结果是有序的,默认从小到大排序,查找的时间复杂度是 l o g 2 n log_2n log2n
- 去重:除了排序,set还有去重的功能。
- 底层1:set存储的实际上是**<value,value>结构**,map才是真正的<key,value>
- 底层2:**set的key值不能修改,因为迭代器底层都是const迭代器。**但是可以插入和删除。
set的函数测试代码
void test_set1()
{
// 排序+去重
set<int> s;
s.insert(3);
s.insert(3);
s.insert(3);
s.insert(5);
s.insert(8);
s.insert(7);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;//3 5 7 8
if (s.find(5) != s.end())
{
cout << "找到了" << endl;
}
if (s.count(5))
{
cout << "找到了" << endl;
}
std::set<int> myset;
std::set<int>::iterator itlow, itup;
for (int i = 1; i < 10; i++)
myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90
myset.insert(35);
// 删除[30 60]
//itlow = myset.lower_bound(30); // >=
//itup = myset.upper_bound(60); // >
//std::pair<std::set<int>::const_iterator, std::set<int>::const_iterator> ret;
auto ret = myset.equal_range(30);//ret的类型是pair
itlow = ret.first;
itup = ret.second;
// [itlow, itup)
cout << *itlow << endl;
cout << *itup << endl;
myset.erase(itlow, itup);
for (auto e : myset)
{
cout << e << " ";
}
cout << endl; // 10 20 70 80 90
}
multiset
注意事项
- 允许有重复的元素
- find()函数查找的值有多个,返回的是多个值的第一个位置(树的结构决定,方便后续插入删除)
测试代码
void test_set2()
{
// 排序
multiset<int> s;
s.insert(3);
s.insert(5);
s.insert(8);
s.insert(7);
s.insert(7);
s.insert(9);
s.insert(7);
for (auto e : s)
{
cout << e << " ";//3 5 7 7 7 8 9
}
cout << endl;
// 返回中序第一个7
auto pos = s.find(7);
while (pos != s.end())
{
cout << *pos << " "; //7 7 7 8 9
++pos;
}
cout << endl;
cout << s.count(7) << endl; //3
}
map
map介绍
-
和set的相同点:
- map中的key是唯一的,并且不能修改
-
默认按照小于的方式对key进行比较
-
map中的元素如果用迭代器去遍历,可以得到一个有序的序列
-
map的底层为平衡搜索树(红黑树),查找效率比较高 O ( l o g 2 N ) O(log_2 N) O(log2N)
-
不同点
- map中的的元素是键值对(真正的)
- 可以通过key修改value的值(底层迭代器并不都是const迭代器)
map的函数测试代码
C++11支持多参数的构造函数隐式类型的转换,但是C++98没有
// 隐式类型的转换
class A
{
public:
A(int a1, int a2)
:_a1(a1)
, _a2(a2)
{}
private:
int _a1;
int _a2;
};
string str1 = "hello";
A aa1 = { 1, 2 };
pair<string, string> kv2 = { "string", "字符串" };
- insert()
多种形式
void test_map1()
{
map<string, string> dict;
pair<string, string> kv1("insert", "插入");
dict.insert(kv1);
dict.insert(pair<string, string>("sort", "排序"));
// C++98
dict.insert(make_pair("string", "字符串"));
// C++11 多参数的构造函数隐式类型转换
dict.insert({ "string", "字符串" });
// 隐式类型的转换
string str1 = "hello";
A aa1 = { 1, 2 };
pair<string, string> kv2 = { "string", "字符串" };
}
] 插入时若map中已经有key,不对value进行覆盖
void test_map2()
{
map<string, string> dict;
dict.insert(make_pair("string", "字符串"));
dict.insert(make_pair("sort", "排序"));
dict.insert(make_pair("insert", "插入"));
// 不插入,不覆盖;插入过程中,只比较key,value是相同无所谓
// key已经有了就不插入了
dict.insert(make_pair("insert", "xxxx"));
auto it = dict.begin();
while (it != dict.end())
{
//cout << (*it).first << ":" << (*it).second << endl;
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
for (const auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
}
operator[],若map中没有该元素,则会先进行插入
void test_map4()
{
map<string, string> dict;
dict.insert(make_pair("string", "字符串"));
dict.insert(make_pair("sort", "排序"));
dict.insert(make_pair("insert", "插入"));
cout << dict["sort"] << endl; // 查找和读
dict["map"]; // 插入
dict["map"] = "映射,地图"; // 修改
dict["insert"] = "xxx"; // 修改
dict["set"] = "集合"; // 插入+修改
}