STL
STL
一、动态数组vector
include
vector是变长数组,支持随机访问,不支持在任意位置O(1)插入。为了保证效率,元素的增删一般应该在末尾进行。
声明
#include <vector>
头文件
vector
vector
struct rec{…};
vector
size()/empty()
size函数返回vector的实际长度(包含的元素个数),empty函数返回一个bool类型,表明vector是否为空。二者的时间复杂度都是O(1)。
所有的STL容器都支持这两个方法,含义也相同,之后我们就不再重复给出。
clear()
clear函数把vector清空。
迭代器(不常用)
迭代器就像STL容器的“指针”,可以用星号*
操作符解除引用。
一个保存int的vector的迭代器声明方法为:
vector
vector的迭代器是“随机访问迭代器”,可以把vector的迭代器与一个整数相加减,其行为和指针的移动类似。可以把vector的两个迭代器相减,其结果也和指针相减类似,得到两个迭代器对应下标之间的距离。
begin()/end()
begin函数返回指向vector中第一个元素的迭代器。例如a是一个非空的vector,则*a.begin()与a[0]的作用相同。
所有的容器都可以视作一个“前闭后开”的结构,end函数返回vector的尾部,即第n个元素再往后的“边界”。*a.end()与a[n]都是越界访问,其中n=a.size()。
遍历vector
下面两份代码都遍历了vector
for (int I = 0; I < a.size(); I ++) cout << a[i] << endl;
for (vector<int>::iterator it = a.begin(); it != a.end(); it ++) cout << *it << endl;
front()/back()
front函数返回vector的第一个元素,等价于*a.begin() 和 a[0]。
back函数返回vector的最后一个元素,等价于*==a.end() 和 a[a.size() – 1]。
push_back() 和 pop_back()
a.push_back(x) 把元素x插入到vector a的尾部。
a.pop_back() 删除vector a的最后一个元素。
二、队列 queue
特点:先进先出
#include <queue>
头文件queue主要包括循环队列queue
和优先队列priority_queue
两个容器。
声明
queue
struct rec{…}; queue
priority_queue
priority_queue<int, vector
priority_queue<pair<int, int>>q;
循环队列 queue
push 从队尾插入
pop 从队头弹出
front 返回队头元素
back 返回队尾元素
优先队列 priority_queue
优先队列:优先往外弹所有数的最大值
push 把元素插入堆
pop 删除堆顶元素
top 查询堆顶元素(最大值)
注:除了队列、优先队列还有栈没有clear()清空函数之外,其它容器都clear()函数
那我们如何清空队列或栈:重新定义即可
queue
q; ....
q = queue
();
双端队列deque
include
双端队列deque是一个支持在两端高效插入或删除元素的连续线性存储空间。它就像是vector和queue的结合。与vector相比,deque在头部增删元素仅需要O(1)的时间;与queue相比,deque像数组一样支持随机访问。
[] 随机访问
begin/end,返回deque的头/尾迭代器
front/back 队头/队尾元素
push_back 从队尾入队
push_front 从队头入队
pop_back 从队尾出队
pop_front 从队头出队
clear 清空队列
三、集合set
#include <set>
头文件set主要包括set和multiset两个容器,分别是“有序集合”和“有序多重集合”,即前者的元素不能重复,而后者可以包含若干个相等的元素。set和multiset的内部实现是一棵红黑树,它们支持的函数基本相同。
声明
set
struct rec{…}; set
multiset
size/empty/clear
与vector类似
迭代器
set和multiset的迭代器称为“双向访问迭代器”,不支持“随机访问”,支持星号(*)解除引用,仅支持”++”和--“两个与算术相关的操作。
设it是一个迭代器,例如set
若把it++,则it会指向“下一个”元素。这里的“下一个”元素是指在元素从小到大排序的结果中,排在it下一名的元素。同理,若把it--,则it将会指向排在“上一个”的元素。
begin/end
返回集合的首、尾迭代器,时间复杂度均为O(1)。
s.begin() 是指向集合中最小元素的迭代器。
s.end() 是指向集合中最大元素的下一个位置的迭代器。换言之,就像vector一样,是一个“前闭后开”的形式。因此--s.end()是指向集合中最大元素的迭代器。
insert
s.insert(x)把一个元素x插入到集合s中,时间复杂度为O(logn)。
在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。
find
s.find(x) 在集合s中查找等于x的元素,并返回指向该元素的迭代器。若不存在,则返回s.end()。时间复杂度为O(logn)。
lower_bound/upper_bound
这两个函数的用法与find类似,但查找的条件略有不同,时间复杂度为 O(logn)。
s.lower_bound(x) 查找大于等于x的元素中最小的一个
,并返回指向该元素的迭代器。
s.upper_bound(x) 查找大于x的元素中最小的一个
,并返回指向该元素的迭代器。
erase
设it是一个迭代器,s.erase(it) 从s中删除迭代器it指向的元素,时间复杂度为O(logn)
设x是一个元素,s.erase(x) 从s中删除所有等于x的元素,时间复杂度为O(k+logn),其中k是被删除的元素个数。
count
s.count(x) 返回集合s中等于x的元素个数,时间复杂度为 O(k +logn),其中k为元素x的个数。
set应用例题
HDU2094产生冠军
有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。
球赛的规则如下:
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。*Input*
输入含有一些选手群,每群选手都以一个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以一对选手名字(中间隔一空格)表示,前者战胜后者。如果n为0,则表示输入结束。
*Output*
对于每个选手群,若你判断出产生了冠军,则在一行中输出“Yes”,否则在一行中输出“No”。
*Sample Input*
3
Alice Bob
Smith John
Alice Smith
5
a c
c d
d e
b e
a d
0*Sample Output*
Yes
No
#include<iostream>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
int main()
{
int n;
while(cin>>n && n)
{
string winner, loser;
set<string>all, lose;
// 比赛结果
while(n--)
{
cin>>winner>>loser;
all.insert(winner);
all.insert(loser);
lose.insert(loser);
}
if(all.size() - lose.size() == 1)
cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
四、map
#include <map>
map容器是一个键值对key-value的映射,其内部实现是一棵以key为关键码的红黑树。Map的key和value可以是任意类型,其中key必须定义小于号运算符。
声明
map<key_type, value_type> name;
例如:
map<long, long, bool> vis;
map<string, int> hash;
map<pair<int, int>, vector
size/empty/clear/begin/end均与set类似。
Insert/erase
与set类似,但其参数均是pair<key_type, value_type>。
find
h.find(x) 在变量名为h的map中查找key为x的二元组。
map容器的迭代器first、second用法
例:
map<string, int> m_stlmap;
m_stlmap[“xiaomi”] = 88;
auto mpit = m_stlmap.begin();
first会得到Map中key的有效值,
second会得到Map中value的有效值。
所以
mpit ->first; // 得到是 string 值是 “xiaomi”
mpit ->second; //得到是 int 值是 88
[]操作符
h[key] 返回key映射的value的引用,时间复杂度为O(logn)。
[]操作符是map最吸引人的地方。我们可以很方便地通过h[key]来得到key对应的value,还可以对h[key]进行赋值操作,改变key对应的value。
map应用例题1、
Sample Input
3
memory
kfc
wind
2
49 memory
49 kfc
48 wind
80 kfc
85 wind
83 memorySample Output
1
2
#include<iostream>
#include<map>
using namespace std;
int main()
{
int n = 0;
while(cin >> n)
{
string s;
for(int i = 0; i < n; i++)
cin>>s;
map<string, int>shop; // shop[s]表示商店s涨价总金额
int m = 0, p;
cin>>m;
while(m--) // 每天进行统计
{
for(int i = 0; i < n; i++) // 遍历所有的商店
{
cin>>p>>s; // 该商店在这一天涨价p
shop[s] += p; // 累计商店s的涨价
}
int rank = 1;
// 遍历map容器
for(map<string, int>::iterator it = shop.begin(); it != shop.end(); it++)
{
if(it->second > shop["memory"]) rank++; // 商店排名靠后一位
}
cout<<rank<<endl;
}
shop.clear();
}
system("pause");
return 0;
}
新浪微博上有个“悄悄关注”,一个用户悄悄关注的人,不出现在这个用户的关注列表上,但系统会推送其悄悄关注的人发表的微博给该用户。现在我们来做一回网络侦探,根据某人的关注列表和其对其他用户的点赞情况,扒出有可能被其悄悄关注的人。
输入格式:
输入首先在第一行给出某用户的关注列表,格式如下:
人数N 用户1 用户2 …… 用户N
其中
N
是不超过5000的正整数,每个用户i
(i
=1, ...,N
)是被其关注的用户的ID,是长度为4位的由数字和英文字母组成的字符串,各项间以空格分隔。之后给出该用户点赞的信息:首先给出一个不超过10000的正整数
M
,随后M
行,每行给出一个被其点赞的用户ID和对该用户的点赞次数(不超过1000),以空格分隔。注意:用户ID是一个用户的唯一身份标识。题目保证在关注列表中没有重复用户,在点赞信息中也没有重复用户。输出格式:
我们认为被该用户点赞次数大于其点赞平均数、且不在其关注列表上的人,很可能是其悄悄关注的人。根据这个假设,请你按用户ID字母序的升序输出可能是其悄悄关注的人,每行1个ID。如果其实并没有这样的人,则输出“Bing Mei You”。
输入样例1:
10 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao 8 Magi 50 Pota 30 LLao 3 Ammy 48 Dave 15 GAO3 31 Zoro 1 Cath 60
输出样例1:
Ammy Cath Pota结
输入样例2:
11 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao Pota 7 Magi 50 Pota 30 LLao 48 Ammy 3 Dave 15 GAO3 31 Zoro 29
输出样例2:
Bing Mei You
#include<iostream>#include<map>#include<set>#include<algorithm>using namespace std;int main() { map<string,int>mp; set<string>s; // 用户ID唯一 int n; cin>>n; for(int i = 0; i < n; i++) { string str; cin>>str; s.insert(str); } int m; int sum = 0; int score; string name; cin>>m; for(int i = 0; i < m; i++) { cin>>name>>score; sum += score; // 点赞用户中在关注列表中没有出现 if(s.find(name) == s.end()) { // 将未在关注列表中的点赞用户与点赞数存到map容器中 mp[name] = score; } } int count = 0; double average = sum / m; //遍历map容器 for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) { if(it->second > average) { cout<< it->first <<endl; count++; } } if(count == 0) cout<<"Bing Mei You"<<endl; return 0;}
注:由于map<string,int>存储是按KEY值的字母顺序排序,所以这里免去了排序的步骤。
Let the Balloon Rise
输入
输入包含多个测试用例。每个测试用例都以数字 N (0 < N < = 1000) 为起点, 分布的气球总数。下 N 行包含一个颜色。气球的颜色是一个多达15个小写字母的字符串。带有 N = 0 的测试用例终止输入, 并且不处理此测试用例.输出
对于每种情况, 在单行上打印最流行问题的气球颜色。保证每个测试用例都有一个唯一的解决方案。示例输入
5
green
red
blue
red
red
3
pink
orange
pink
0样例输出
red
pink
思路:map<string , int >颜色对应出现的次数
#include<iostream>#include<map>#include<set>#include<algorithm>using namespace std;int main() { int n; while(cin>>n && n) { map<string,int>mp; for(int i = 0; i < n; i++) { string color; cin>>color; mp[color] ++;// 统计不同颜色出现的次数(value) } int max = 0; string ans; for(map<string,int>::iterator it = mp.begin(); it != mp.end(); it++) { if(it->second > max) { max = it->second; ans = it->first; } } cout<<ans<<endl; } return 0;}
五、pair用法与总结
CSDN参考:
[https://blog.csdn.net/weixin_43222324/article/details/112009043]: