一、set的介绍
1.概念
在C++中,std::set
是标准模板库(STL)中的一个关联容器,用于存储唯一的元素,并且这些元素会按照特定顺序自动排序。
2.基本特性
1)唯一性:std::set
中的元素是唯一的,不允许重复。如果尝试插入重复的元素,插入操作会失败。
2)自动排序:std::set
内部会根据元素的值自动排序,排序规则默认是按照元素类型的 <
运算符来比较。也可以通过自定义比较函数来改变排序规则。
3)基于红黑树实现:std::set
内部通常使用红黑树(一种自平衡的二叉搜索树)来存储元素,因此插入、删除和查找操作的时间复杂度都是 O(log n),其中 n 是容器中元素的数量。
3.代码运用
由于此处内容较为简单且知识点零碎,我将知识点放到了代码的注释里
插入、查找的看这里:
#include<iostream>
#include<set>
using namespace std;
int main()
{// 去重+升序排序set<int> s = { 5,9,3,6,2,3,9,8,7,4,5 };//支持迭代器//set<int>::iterator it = s.begin();auto it = s.begin();while (it != s.end()){cout << *it <<" ";++it;}cout << endl;s.insert(18);s.insert(2);s.insert(4);s.insert(10);//支持范围forfor (auto e : s){cout << e << " ";}cout << endl;//插入一段initializer_list列表值,已经存在的值插入失败s.insert({ 6,9,6,5,10,20,30,35 });for (auto e : s){cout << e << " ";}cout << endl;// 还可以遍历string比较ascll码大小顺序遍历的set<string> sset = { "hello","left","right","haha" };for (auto e : sset){cout << e <<" ";}cout << endl;//与std标准库中的find的对比//std标准库:暴力查找,O(N)auto it1 = find(s.begin(), s.end(),3);//set自带的:类似于二分查找,查找方式类比搜索二叉树,O(logN)auto it2 = s.find(3);return 0;
}
单个数据删除的内容看这里:
int main()
{set<int> s = { 4,2,6,8,5,3,4,1,2,7 };for (auto e : s){cout << e << " ";}cout << endl;// 删除最小值s.erase(4);for (auto e : s){cout << e << " ";}cout << endl;s.erase(s.begin()); //删除s的第一个元素,不要看你输入元素的顺序!!!for (auto e : s){cout << e << " ";}cout << endl;// 直接删除xint x;cin >> x;int num = s.erase(x);if (num == 0){cout << x << "不存在" << endl;}for (auto e : s){cout << e << " ";}cout << endl;// 直接查找在利用迭代器删除xint y;cin >> y;auto pos = s.find(y);if (pos != s.end()){s.erase(pos);}else{cout << y << "不存在!" << endl;}for (auto e : s){cout << e << " ";}cout << endl;//用count()函数统计z的出现次数,进而判断是否存在int z = 0;cin >> z;if (s.count(z)){cout << x << "在!" << endl;}else{cout << x << "不存在!" << endl;}return 0;
}
区间数据删除看这里:
int main()
{set<int> s = { 10,60,25,36,92,35,45,56,30,66,77,88,99 };for (auto e : s){cout << e << " ";}cout << endl;// 实现查找到的[itlow,itup)包含[30, 60]区间// 返回 >= 30auto itlow = s.lower_bound(30);// 返回 > 60auto itup = s.upper_bound(60);// 删除这段区间的值s.erase(itlow, itup);for (auto e : s){cout << e << " ";}cout << endl;return 0;
}
二、miltiset的介绍
1.概念
std::multiset
是 C++ STL 中的一个关联容器,用于存储可重复的元素,并且这些元素会根据指定的比较准则自动排序。基本用法跟set差不多,具体见代码示例
2.代码示例
int main()
{//multiset也是在<set>头文件中multiset<int> ms = { 1,2,6,5,3,2,7,8,9,7,2,7 };//迭代器和范围for均支持multiset<int>::iterator it = ms.begin();while (it != ms.end()){cout << *it << " ";it++;}cout << endl;// 相比set不同的是,x可能会存在多个,find查找中序的第一个int x;cin >> x;auto pos = ms.find(x);while (pos != ms.end() && *pos == x){cout << *pos << " ";++pos;}cout << endl;//相比set不同的是,count会返回x的实际个数cout << ms.count(x)<<endl;// 相比set不同的是,erase给值时会删除所有的xms.erase(x);for (auto e : ms){cout << e << " ";}cout << endl;return 0;
}
三、map的介绍
1.概念
在C++中,std::map
是一个非常强大的容器,属于标准模板库(STL)的一部分。它是一个基于红黑树实现的关联容器,用于存储键值对(key-value
),并且保证键的唯一性。
2.基本特性:
1)键值对存储:std::map
存储的是键值对,每个键(key
)唯一,通过键可以快速访问对应的值(value
)。
2)有序性:std::map
是有序的,它会根据键的值自动排序。默认情况下,它使用键的 <
操作符来比较键的大小。
3)基于红黑树:std::map
内部是通过红黑树实现的,因此插入、删除和查找操作的时间复杂度都是 O(log n)。
3.代码示例
3.1 pair 的介绍
在C++中,std::pair
是一个非常实用的模板类,用于将两个不同类型的数据组合在一起。它属于标准模板库(STL)的一部分,通常用于需要同时处理两个相关数据的场景。
std::pair
提供了两个成员变量:
-
first
:存储第一个数据。 -
second
:存储第二个数据。
3.2 插入部分
#include<iostream>
#include<map>
using namespace std;
int main()
{map<string, string> m;//c++98//方法一pair<string, string> p1("left", "左边");m.insert(p1);//方法二m.insert(pair<string, string>("right", "右边"));//方法三m.insert(make_pair("up", "上"));//c++11//方法四m.insert({ "down","下" });//map<string, string>::iterator it = m.begin();auto it = m.begin();while (it != m.end()){cout << it->first << " " << it->second << endl;//实际上是这样的,重载->,为了可读性,省略一个->//cout << it.operator->()->first << " " << it.operator->()->second << endl;it++;}cout << endl;return 0;
}
插入有一个点值得注意一下: 如果插入的“键值对”在原map中已经有了,则本次插入失败,即key相同,插入失败,value相同,可以插入
我们看如下示例:
运行结果如下:
四、运用
map这个数据结构是具有映射性质的,很多具有关联的东西都可以用map来解决,这里我们以计次问题为例,来感受一下map的妙处所在!
1.水果计次问题
现在我们给出一些水果,需要统计一下次数,这里给出代码示例
int main()
{string arr[] = { "苹果", "西瓜", "香蕉", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };map<string, int> cmap;for (auto& e : arr){auto it = cmap.find(e);if (it == cmap.end()) //证明之前插入的没有这个水果,我现在要插入{cmap.insert({e,1});}else //证明之前插入过这个水果了,次数增加一次即可{it->second++;}}for (auto e : cmap){cout << e.first << " " << e.second << endl;}return 0;
}
这种方法是大家都能想到的,但是可能代码要写好长,感觉费时间,因此我们改进一下
2.[ ]的介绍
std::map
的 []
运算符是一种非常重要的成员函数,用于访问或插入元素。
1)如果 key
已经存在于 map
中,[]
运算符会返回对应键的值的引用。
2)如果 key
不存在,[]
运算符会插入一个新的键值对,键为 key
,值为 ValueType
的默认构造值(例如,如果 ValueType
是 int
,则默认值为 0
),并返回这个新值的引用。
3.【】的应用
map<string, string> dict;// 插入(基本不会这样用)dict["left"];// 插入+修改dict["up"] = "上";for (auto e : dict){cout << e.first << " " << e.second << endl;}cout << endl;// 修改dict["left"] = "左边";// 查找,输出对应的值cout << dict["left"] << endl;cout << dict["up"] << endl;
运行结果如下
4.代码更改
int main()
{string arr[] = { "苹果", "西瓜", "香蕉", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };map<string, int> cmap;for (auto e : arr){cmap[e]++;}for (auto e : cmap){cout << e.first << " " << e.second << endl;}return 0;
}
说明:在上述代码中,如果我的水果已经存在了,那么【】会返回对应水果(键)的次数(值)的引用,并通过++完成自增,如果我的水果在之前是没有出现过的,那cmap中会插入一个新的键值对,键为 水果名称,值为 次数,并返回这个新值的引用,在通过++完成自增计数
我们可以在插入几个水果试一试:
pair<map<string, int>::iterator, bool> r1 = cmap.insert({ "草莓", 1 });pair<map<string, int>::iterator, bool> r2 = cmap.insert({ "西瓜", 1 });pair<map<string,int>::iterator, int> r3 = cmap.insert({ "蓝莓",10 });for (auto e : cmap){cout << e.first << " " << e.second << endl;}
五、multimap
multimap与map的区别我们可以类比mutiset和set的区别,这里我们不多说了,直接看一下代码!
int main()
{map<string, string> ant;ant.insert({ "black","white" });ant.insert({ "dirty","clean" });ant.insert({ "dirty","tidy" });ant.insert(pair<string, string>("dirty", "neat"));for (auto e : ant){cout << e.first << "<->" << e.second << endl;}cout << endl;multimap<string, string> mant;mant.insert({ "black","white" });mant.insert({ "dirty","clean" });mant.insert({ "dirty","tidy" });mant.insert(pair<string, string>("dirty", "neat"));//以上两种方式都可以插入,但个人更倾向于隐式类型转换(第一种)for (auto e : mant){cout << e.first << "<->" << e.second << endl;}return 0;
}
结果如下:
下面这个大家看一下就好,这里不在多说了
int main()
{std::multimap<char, int> mymm;mymm.insert(std::pair<char, int>('a', 10));mymm.insert(std::pair<char, int>('b', 20));mymm.insert(std::pair<char, int>('b', 30));mymm.insert(std::pair<char, int>('b', 40));mymm.insert(std::pair<char, int>('c', 50));mymm.insert(std::pair<char, int>('c', 60));mymm.insert(std::pair<char, int>('d', 60));std::cout << "mymm contains:\n";for (char ch = 'a'; ch <= 'd'; ch++){std::pair <std::multimap<char, int>::iterator, std::multimap<char, int>::iterator> ret;ret = mymm.equal_range(ch);std::cout << ch << " =>";for (std::multimap<char, int>::iterator it = ret.first; it != ret.second; ++it)std::cout << ' ' << it->second;std::cout << '\n';}return 0;
}
结果如下: