一、set(multiset)的基本知识和使用
set也是一种我们直接可以使用的容器,使用应该包含 #include <set> 这个头文件。此处暂且不讨论其底层,只探讨set如何使用即可。
我们看到,set 的模板参数有三个,第一个就是其存储的数据类型,第二个是仿函数,决定到时候排序的逻辑,第三个是空间配置器,我们在使用中着重写第一个,而后两个我们目前的学习程度几乎用不到。
1. set的构造
我们可以看到,set的构造基本上和我们学的vector,list等容器的构造类似,因为set也是支持迭代器的,所以也是很简单的。
2. set的增删查
我们来看看下面的代码:
int main()
{
set<int> s1;
//set的插入
s1.insert(4);
s1.insert(1);
s1.insert(9);
s1.insert(5);
for (auto a : s1)
{
cout << a << " ";
}
cout << endl;
auto found1 = s1.find(10);//找不到即返回end()
if (found1 == s1.end())
cout << "找不到" << endl;
auto found2 = s1.find(5);
s1.erase(found2);//支持迭代器删除
s1.erase(4);//支持直接删除内容
//注意,删除同样会导致迭代器失效
for (auto a : s1)
{
cout << a << " ";
}
cout << endl;
return 0;
}
运行结果:
set在插入过程中,底层已经按照升序,将插入的内容排号顺序了,我们在删除的过程中,set仍然保持着升序。需要注意的是,当我们使用find功能时,如果没有查找到,则会返回set的end()迭代器。同样的,erase也支持迭代器区间删除,如果执行 erase(s1.begin(),s1.end()); 那么我们将删除set中所有的元素。
multiset和set的使用基本完全类似,因为set是不能接受相同的值的,也就是说我们如果插入了一个set中已经存在的值,那么我们会插入失败,而multiset不会插入失败,因为multiset支持值冗余。结果就是二者均会默认升序,而set会去重,multiset不会。
再是multiset中的find和erase功能,其中由于multiset会存在多个值,因此find返回的是其 中序第一个值得迭代器。而erase删除时,如果该值存在多个,erase会将其全部删除。
二、map的基本知识和使用
这是map的声明,Key就是map底层关键字的类型,而T是map底层value的类型,同理set,一般情况下我们不需要传入后两个模板参数,只需要传入Key 和 T 即可。
1.pair类型
map的底层数据存储,是用pair<Key,T>来存储键值对数据。
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)
{}
template<class U, class V>
pair(const pair<U, V>& pr)
: first(pr.first)
, second(pr.second)
{}
};
这就是pair的简单实现,我们从上面就可以看出来,pair内可以存储两个分别为T1 和 T2 类型的数据,而map的插入或者构造是需要pair的。
2. map的构造
还是一样,构造和前面没什么太大的区别,我们直接来看map的增删查改。
3.map的增删查
int main()
{
map<string, string> m1;
pair<string, string> p1("地图", "map");
m1.insert(p1);
m1.insert(pair<string, string>("你好", "hello"));
m1.insert({ "自动的","auto" });
for (auto a : m1)
{
cout << a.first << "->" << a.second << endl;
}
return 0;
}
运行结果:
map在插入过程中,会按照Key的大小进行自动排序,因此map一定程度上也可以帮助我们实现排序有关功能。
m1.erase("你好");
auto found = m1.find("地图");
cout << found->first << "->" << found->second << endl;
cout << endl;
for (auto a : m1)
{
cout << a.first << "->" << a.second << endl;
}
运行结果如下:
也就是说,map的增删查和set基本一致,要注意的是map的插入是一个pair的类型,而删除和查找,只对map的Key有效,我们不能使用map的value来进行删除和查找。
4. map的[]功能样例
我们来看下面的代码:
int main()
{
map<string, int> countMap;
string arr[] = { "苹果","香蕉", "凤梨", "苹果", "猕猴桃", "香蕉", "苹果" };
for (const auto& str : arr)
{
countMap[str]++;
}
for (const auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
//修改凤梨的个数
countMap["凤梨"] = 20;
cout << endl;
for (const auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
return 0;
}
运行结果如下:
这是我们一个统计水果个数的简单代码,通过map来实现,我们在下面也通过了[]来实现了修改map中Key值对应的value的数据,那么map中的[]该如何理解呢?
其实本质很简单,[]是运算符重载,如果map中没有[]中的Key值,例如上方在[]中写的str,那么我们就会插入该Key值,对应的value值是value所对类型的默认值,然后我们可以对该Key所对的value进行修改例如上方的++。如果Key已经存在,那么我们就只能对齐value进行修改,例如上方对凤梨个数的修改。
此时map中没有西瓜这个水果,也就是没有西瓜这个Key,那么我们只进行countMap["西瓜"];操作,会发生什么呢?完全正确,map会插入西瓜作为Key而其对应的value类型为int,其默认值为0,所以到时我们打印出来的就是 西瓜:0。
以上内容如有错误,欢迎批评指正!