map

map 是一种映射容器,其头文件是 map

功能 说明
map<x,y> m 建立一个名字为 mm 的映射,下标类型为 x,元素类型为 y
m[x]=y mxm_x 的值设为 yy
m.find(x)!=a.end() 判断 mxm_x 是否存在
m.erase(x) mxm_x 删除
m.clear() 清空 mm
m.size() 返回 mm 中的元素数量

遍历 map 可以使用迭代器。

map<int,int> m;
for(map<int,int>::iterator i=m.begin();i!=m.end();i++){
	int id=i->first; //id 为下标
  	int value=i->second;//value 为元素
}

其中 map<int,int>::iterator 在使用 C++11 以上时可替换为 auto,CSP-J/S 及 NOIP 等比赛可以使用。auto 为自动类型推断,请勿滥用 auto

map 底层为二叉平衡树(红黑树),因此单次操作时间复杂度为 O(logn)O(\log n)

set

set 是一个 不可重 集合,其头文件是 set

功能 说明
set<x> s 建立一个名字为 ss 的集合,元素类型为 x
s.insert(x) xx 插入集合
s.find(x)!=a.end() 判断 xx 是否在集合中
s.erase(x) xx 从集合中删除删除
s.clear() 清空 ss
s.size() 返回 ss 中的元素数量

遍历 set 可以使用迭代器。

set<int> s;
for(set<int>::iterator i=s.begin();i!=s.end();i++){
	int value=*i;
}

set 会自动将元素去重并进行升序排序。

map 底层为二叉平衡树,因此单次操作时间复杂度为 O(logn)O(\log n)

multiset

multisetset 类似,但是 multiset可重的,其头文件是 set

由于 multiset 是可重的,所以做删除操作有两种情况,分别是删除所有值为 x 的元素,和删除一个值为 x 的元素。

s.erase(x) //删除所有值为 x 的元素
if(s.find(x)!=s.end()){
    s.erase(s.find(x)); //删除一个值为 x 的元素
}

可以通过 lower_bound() 函数与 upper_bound() 函数查询 mutisetx 的前驱及后继。

set<int>::iterator it=s.lower_bound(x);
it--;
int pre=*it; //前驱
set<int>::iterator it=s.upper_bound(x);
int nxt=*it; //后继

priority_queue

priority_queue 是一个优先队列,在头文件 queue 中。

优先队列是一个弹出元素时弹出最大值的数据结构。

priority_queue 可在 O(logn)O(\log n) 的时间复杂度插入元素,在 O(1)O(1) 的时间复杂度获取/弹出队首元素。

功能 说明
priority_queue<x> q 建立一个名字为 qq 的优先队列,元素类型为 x,队首为最大值。
priority_queue<x,vector<x>,greater<x> > q 建立一个名字为 qq 的优先队列,元素类型为 x,队首为最小值。
q.top() 获取队首元素
q.pop() 获取队首元素
q.size() 返回 qq 中的元素数量
q.push(x) 将元素 xx 插入到 qq

例题:【模板】堆

给定一个数列,初始为空,请支持下面三种操作:

  1. 给定一个整数 xx,请将 xx 加入到数列中。
  2. 输出数列中最小的数。
  3. 删除数列中最小的数(如果有多个数最小,只删除 11 个)。

思路:使用 priority_queue<int,vector<int>,greater<int> > q 让最小值放在队首,按照题目说明及上方表格完成操作。


例题:合并果子

通过模拟合并的过程,我们会发现每次选择两个最小的元素合并成较大的元素是最优策略,可以由哈夫曼编码证明(具体请参考《深基》)

因而,每次从序列中找到最小值和次小值,将其相加再放入序列中即可。时间复杂度为 O(nlogn)O(n \log n)