STL

STL

一、动态数组vector

include

vector是变长数组,支持随机访问,不支持在任意位置O(1)插入。为了保证效率,元素的增删一般应该在末尾进行。

声明

#include <vector> 头文件

​ vector a; 相当于一个长度动态变化的int数组

​ vector b[233]; 相当于第一维长233,第二位长度动态变化的int数组

​ struct rec{…};

​ vector c; 自定义的结构体类型也可以保存在vector中

size()/empty()

size函数返回vector的实际长度(包含的元素个数),empty函数返回一个bool类型,表明vector是否为空。二者的时间复杂度都是O(1)。

所有的STL容器都支持这两个方法,含义也相同,之后我们就不再重复给出。

clear()

​ clear函数把vector清空。

迭代器(不常用)

​ 迭代器就像STL容器的“指针”,可以用星号*操作符解除引用。

​ 一个保存int的vector的迭代器声明方法为:

​ vector::iterator it;

vector的迭代器是“随机访问迭代器”,可以把vector的迭代器与一个整数相加减,其行为和指针的移动类似。可以把vector的两个迭代器相减,其结果也和指针相减类似,得到两个迭代器对应下标之间的距离。

begin()/end()

begin函数返回指向vector中第一个元素的迭代器。例如a是一个非空的vector,则*a.begin()与a[0]的作用相同。

所有的容器都可以视作一个“前闭后开”的结构,end函数返回vector的尾部,即第n个元素再往后的“边界”。*a.end()与a[n]都是越界访问,其中n=a.size()。

遍历vector

下面两份代码都遍历了vectora,并输出它的所有元素。

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 q;

​ struct rec{…}; queue q; //结构体rec中必须定义小于号

​ priority_queue q; // 大根堆(每次弹出最大元素)

​ priority_queue<int, vector, greater q; // 小根堆

​ priority_queue<pair<int, int>>q;

循环队列 queue

​ push 从队尾插入

​ pop 从队头弹出

​ front 返回队头元素

​ back 返回队尾元素

优先队列 priority_queue

优先队列:优先往外弹所有数的最大值

​ push 把元素插入堆

​ pop 删除堆顶元素

​ top 查询堆顶元素(最大值)

注:除了队列、优先队列还有栈没有clear()清空函数之外,其它容器都clear()函数

那我们如何清空队列或栈:重新定义即可

queueq;

....

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 s;

struct rec{…}; set s; // 结构体rec中必须定义小于号

multiset s;

size/empty/clear

​ 与vector类似

迭代器

set和multiset的迭代器称为“双向访问迭代器”,不支持“随机访问”,支持星号(*)解除引用,仅支持”++”和--“两个与算术相关的操作。

设it是一个迭代器,例如set::iterator it;

若把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

image

#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> test;

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、

image

Sample Input
3
memory
kfc
wind
2
49 memory
49 kfc
48 wind
80 kfc
85 wind
83 memory

Sample 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的正整数,每个用户ii=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]:

posted @ 2021-09-12 23:18  时间最考验人  阅读(94)  评论(0编辑  收藏  举报