set和map
- set
- 什么是set
- set的使用
- 关联式容器
- 键值对
- map
- 什么是map
- map的使用
- map的插入方式
- 常用功能
- map[] 的灵活使用
set
什么是set
set是STL中一个底层为二叉搜索树来实现的容器
- 若要使用set需要包含头文件
#include<set>
- set中的元素具有唯一性(因此可以用set去重)
- 若用set的迭代器遍历,默认得到升序序列
- set查找某个元素默认复杂度为 l o g 2 N log_2 N log2N
- set中的元素不能被修改
set的使用
set<int> s; //默认升序
set<int , greater<int>> us; //降序
int i;s.insert(i); //插入值 若成功,则返回i所在迭代器,若失败,则返回已存在的i的迭代器s.erase(i); //删除某个值 并 返回所删除的个数s.clear(); //清空ss.begin(); //begin迭代器s.end(); //end()迭代器s.find(i); //查找i,若找到了,则返回i的迭代器,若没找到,返回尾部迭代器 s.end();s.empty(); //返回s是否为空s.size(); //返回s内元素个数
用例:
#include<iostream>
#include<set>using namespace std;int main()
{set<int> s;s.insert(1);s.insert(3);s.insert(2);s.insert(4);s.insert(5);s.insert(1); //插入第二个1//这里用了范围for ,因为右迭代器,因此自动遍历for (auto& e : s){cout << e << " ";}cout << endl; //遍历结果: 1 2 3 4 5//删除3再遍历 set会自动调整s.erase(3);for (auto& e : s){cout << e << " ";}cout << endl; //遍历结果: 1 2 4 5//清理ss.clear();for (auto& e : s){cout << e << " ";}cout << endl; //空值set<int, greater<int>> us; //降序set//插入:us.insert(1);us.insert(2);us.insert(3);us.insert(4);us.insert(5);//遍历for (auto& e : us){cout << e << " ";}cout << endl; //遍历结果为降序: 5 4 3 2 1return 0;
}
关联式容器
之前学习的容器中,基本都是单元素存储,比如:vector、list、deque、等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。即 K 模型 的容器
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高
例如上面的set也是关联式容器,set中只放value,但在底层实际存放的是由<value, value>构成的键值对
键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息.即 KV 模型 的容器
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)
{}
};
map
什么是map
一种存储键值对,底层为二叉搜索树的数据结构
- 需要包含头文件
#include<map>
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
即 KV 模型
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:
typedef pair<const key, T> value_type
其中,key为const,因此是不能修改的,而T是可以修改的 - map中的元素
按照键值key进行比较排序
。 - map支持下标访问,即在[]中放入key,就可以找到与key对应的value。
- map底层实际上就是二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
map的使用
先创建一个map对象:
map<string, string> m;
map的插入方式
几种常见的map插入方式:
m.insert(make_pair("left", "左边"));m.insert(pair<string, string>("right", "右边"));m["insert"] = "插入";
-
因为map中存储的是键值对元素,因此每次插入的时候应该使用pair函数
m.insert(pair<string, string>("right", "右边"));
但是这种方法有点麻烦,因此引用了make_pair函数 -
make_pair是一个仿函数,定义如下:
返回值还是一个pair键值对:
因此当map插入值的时候可以使用以下方法:
m.insert(make_pair("left", "左边"));
这种方式是最常用的 -
因为map重载了[],因此可以直接使用[]来进行插入
map中operator[]的原理是:
- 用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中
- 如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
- 如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
- operator[]函数最后将insert返回值键值对中的value返回
m["insert"] = "插入";
其中,[]内为 K 值, 返回的V被 = 后的内容赋值;
常用功能
m.insert(make_pair("erase", "删除")); //插入值 若已存在,则返回该值的迭代器m.erase("erase"); //删除值m.clear(); //清除mapm.size(); //返回 K 元素的数量m.begin(); //begin迭代器m.end(); //end迭代器m.find("erase"); //查找 K 值,若找到了,则返回迭代器, 若没找到,则返回迭代器m.end()m["find"]; //插入K ,若有m.swap(m2); //交换两个map对象 其中m2 为另一个与m对象同类型的对象
map[] 的灵活使用
map因为重载了[] ,因此变得非常灵活,例如,统计下列数组中相同的值出现的次数:
#include<iostream>
#include<string>
#include<map>using namespace std;int main()
{string arr[] = { "西瓜","西瓜", "西瓜", "西瓜","苹果","苹果","苹果","苹果","苹果","苹果","香蕉","香蕉","香蕉","香蕉","草莓","草莓","草莓","草莓","草莓","草莓","草莓", };map<string, int> m;for (auto& e : arr){m[e]++; //这里直接利用[]对m进行插入,并通过++ 对V值进行控制}for (auto& e : m){cout << e.first << ":" << e.second << endl;}return 0;
}
输出结果: