寒假集训一期(4)—— c++【STL栈和队列】基本操作函数和模板习题


一、 vector 动态数组

简单来说,vector是一个没有长度限制的数组,也叫不定长数组。

常见操作

函数功能
c.clear()移除容器中所有数据
c.empty()判断容器是否为空
c.erase(pos)删除pos位置的数据
c.erase(begin,end)删除[begin,end]区间的数据
c.front()传回第一个数据
c.insert(pos,elem)在pos位置插入一个elem拷贝
c.pop_back()删除最后一个数据
c.push_back(elem)在尾部加入一个数据
c.resize(num)重新设置该容器的大小
c.size()返回容器中实际数据的个数
c.begin()返回指向容器第一个元素的迭代器
c.end()返回指向容器最后一个元素的迭代器

如何定义二维vector

有两种方法:
法一:

int n = 5, m = 6;
vector<vector<int>> obj(n);//定义类型为vector的vector
for(int i = 0; i < obj.size(); i++){
	obj[i].resize(m);//实现二维
}

法二:

int n = 5, m = 6;
vector<vector<int>> obj(n, vector<int>(m));//直接定义二维

结构体二维vector

定义一个类型为结构体名字的vector即可

struct node{
	int x, y, z;
}tmp;
vector<node>a;//这里的node就是结构体上的node

今天讲一下STL里面的栈和队列的基本操作,栈和队列都是一种数据结构,他们的共同点是都是线性结构,当然,他俩也有不同的地方,栈是一种先进后出的数据结构,而队列则是一种先进先出的数据结构。

一、栈和队列

可以这样来说,队列就像一个羽毛球盒,从一边放进去就从另一边拿出来,如果从放进去的那一边一边拿,就会造成羽毛损坏,如图
在这里插入图片描述

而栈则可以看成一个乒乓球盒,也就是说乒乓球盒只有一个口,越先放进去就会被压到最下面,从而就会越后出来,如图
在这里插入图片描述

CSP-J第一轮常考题

在这里插入图片描述
这道题虽然看起来有点难懂,但他确是一道栈的题目,也就是说,我们可以吧弹夹看做一个栈,子弹也就是元素,每将一个子弹放入弹夹,就相当于一个元素入栈,这道题目实际上就是在问下列哪一个出栈顺序是不合法的,我们遇到这样的题目可以画一个示意图:
A:在这里插入图片描述
所以合法;
B:在这里插入图片描述
所以合法。
C:在这里插入图片描述
D:在这里插入图片描述

做题方法总结——模拟

这道题可以让我们更深刻的理解栈的基本概念。遇到这种题目,我们可以利用栈的概念解决,首先先找准目前没有进过栈的第一个数,然后将目前未进栈元素到我们刚刚找的那个元素全部依次进栈,然后查看出栈顺序是否合法,依次模拟,即可得出结果。

二、栈的基本操作函数

push 元素入栈

push元素入栈
pop栈顶元素出栈
front获取栈底元素
size获取栈长度
empty栈判空

三、队列的基本操作函数

push元素入队列
pop队尾元素出栈
front获取队头元素
size获取队列长度
empty队列判空
top获取队尾元素

双端队列

顾名思义,可以从两边进,两边出

操作解释
push_back()在队尾压入元素
push_front():在队头压入元素
pop_back():删除最后一个元素
pop_front():删除第一个元素
front():返回第一个元素的引用
back():返回最后一个元素的引用

优先队列

优先队列是队列的一种,他是自动帮我们排序的,内部结构是大根堆,常见操作与一般的队列一样,但是定义方式有所不同
如:prioriyt_queue<int> q;
此外,我们经常为了适应题目背景,重载优先队列的排序顺序,一般是在结构体内实现的,大致如下

struct cmp{
	bool operator ()(int a, int b){
		return (a % 100) > (b % 100);
	}
};
void main(){
	priority_queue<int , vector<int>, cmp >q;
}

如果想要把结构体与优先队列结合起来,那么就需要重载小于符号,具体思想和上面差不多,格式如下:

struct node{
	int x, y;
	bool operator < (const node &a) const{
		//这里的node和结构体名字一样
		return x < a.x;
	}
}; 

除了定义在结构体以内,也可以定义一个专门用来做比较的结构体,只需要把刚刚重载运算符的部分提到cmp函数内,然后在定义有限队列是加上cmp即可,如下:

struct node{
	int to, cost;
};
struct cmp{
	bool operator ()(node a, node b){
		return a.cost > b.cost;
	}
};
priority_queue<node, vector<node>, cmp> priq;

四、题目

数组逆序重存放

题目描述

将一个数组中的值按逆序重新存放。例如,原来的顺序为 8 , 6 , 5 , 4 , 1 8,6,5,4,1 8,6,5,4,1。要求改为 1 , 4 , 5 , 6 , 8 1,4,5,6,8 1,4,5,6,8

输入格式

输入为两行:第一行数组中元素的个数 n n n 1 < n ≤ 100 1 \lt n \le 100 1<n100),第二行是 n n n 个整数,每两个整数之间用空格分隔。

输出格式

输出为一行:输出逆序后数组的整数,每两个整数之间用空格分隔。

样例 #1

样例输入 #1

5
8 6 5 4 1

样例输出 #1

1 4 5 6 8

这道题非常简单,其方法也很多,最常见的方法就是用数组存储,但是这道题的题意刚好符合我们的栈,为了拿栈练练手,这道题我们用栈做:

分析:

我们只需要利用栈先进后出的特点,将输入的数字依次入栈,最后在依次出栈输出即可:直接给代码

#include<bits/stdc++.h>
using namespace std;
int i,a,x;
stack<int>h;
int main(){
	ios::sync_with_stdio(false);
	cin>>a;
	for(i=0;i<a;i++){
		cin>>x;
		h.push(x);
	}
	for(i=0;i<a;i++){
		x=h.top();
		h.pop();
		cout<<x<<" ";
	}
}

【模板】栈

题目描述

请你实现一个栈(stack),支持如下操作:

  • push(x):向栈中加入一个数 x x x
  • pop():将栈顶弹出。如果此时栈为空则不进行弹出操作,输出 Empty
  • query():输出栈顶元素,如果此时栈为空则输出 Anguei!
  • size():输出此时栈内元素个数。

输入格式

本题单测试点内有多组数据
输入第一行是一个整数 T T T,表示数据组数。对于每组数据,格式如下:
每组数据第一行是一个整数,表示操作的次数 n n n
接下来 n n n 行,每行首先由一个字符串,为 pushpopquerysize 之一。若为 push,则其后有一个整数 x x x,表示要被加入的数, x x x 和字符串之间用空格隔开;若不是 push,则本行没有其它内容。

输出格式

对于每组数据,按照「题目描述」中的要求依次输出。每次输出占一行。

样例 #1

样例输入 #1

2
5
push 2
query
size
pop
query
3
pop
query
size

样例输出 #1

2
1
Anguei!
Empty
Anguei!
0

提示

样例 1 解释
对于第二组数据,始终为空,所以 popquery 均需要输出对应字符串。栈的 size 为 0。

数据规模与约定

对于全部的测试点,保证 1 ≤ T , n ≤ 1 0 6 1 \leq T, n\leq 10^6 1T,n106,且单个测试点内的 n n n 之和不超过 1 0 6 10^6 106,即 ∑ n ≤ 1 0 6 \sum n \leq 10^6 n106。保证 0 ≤ x < 2 64 0 \leq x \lt 2^{64} 0x<264

提示

  • 请注意大量数据读入对程序效率造成的影响。
  • 因为一开始数据造错了,请注意输出的 Empty 不含叹号,Anguei! 含有叹号。
分析

这是一道普及模板题,这道题目是让我们用栈来实现一个栈,这听起来非常拗口,但做起来非常容易,只需要判断输入的是什么指令,在利用栈实现即可:

注意

这道题需要注意一个地方,他会有很多次指令,再一次指令弄完以后,一定要记得清空栈哦!

//B3614【模板】栈 
#include<bits/stdc++.h>
using namespace std;
int n,i,j,k,x,z;
string c;
stack<int>h;
int main(){
	ios::sync_with_stdio(false);
	cin>>n;
	for(i=1;i<=n;i++){
		cin>>k;
		for(j=1;j<=k;j++){
			for(z=1;z<=h.size();z++)//清空栈
				h.top();
			cin>>c;
			if(c=="push"){
				cin>>x;
				h.push(x);
				continue;
			}
			if(c=="pop"){
				if(!h.size()){
					cout<<"Empty"<<endl;
					continue;
				}
				else 
					h.pop();	
			}
			if(c=="query"){
				if(h.size()==0){
					cout<<"Anguei!"<<endl;
					continue;
				}
				else {
					cout<<h.top()<<endl;
					continue;
				}
			}
			if(c=="size")
				cout<<h.size()<<endl;
		}
	}
}

【模板】队列

题目描述

请你实现一个队列(queue),支持如下操作:

  • push(x):向队列中加入一个数 x x x
  • pop():将队首弹出。如果此时队列为空,则不进行弹出操作,并输出 ERR_CANNOT_POP
  • query():输出队首元素。如果此时队首为空,则输出 ERR_CANNOT_QUERY
  • size():输出此时队列内元素个数。

输入格式

第一行,一个整数 n n n,表示操作的次数。

接下来 n n n 行,每行表示一个操作。格式如下:

  • 1 x,表示将元素 x 加入队列。
  • 2,表示将队首弹出队列。
  • 3,表示查询队首。
  • 4,表示查询队列内元素个数。

输出格式

输出若干行,对于每个操作,按「题目描述」输出结果。

每条输出之间应当用空行隔开。

样例 #1

样例输入 #1

13
1 2
3
4
1 233
3
2
3
2
4
3
2
1 144
3

样例输出 #1

2
1
2
233
0
ERR_CANNOT_QUERY
ERR_CANNOT_POP
144

提示

样例解释
首先插入 2,队首为 2、队列内元素个数为 1
插入 233,此时队首为 2
弹出队首,此时队首为 233
弹出队首,此时队首为空。
再次尝试弹出队首,由于队列已经为空,此时无法弹出。
插入 144,此时队首为 144

数据规模与约定

对于 100 % 100\% 100% 的测试数据,满足 n ≤ 10000 n\leq 10000 n10000,且被插入队列的所有元素值是 [ 1 , 1000000 ] [1, 1000000] [1,1000000] 以内的正整数。

分析

这道题依旧是一道模板题,本题就比较仁慈了,不用每次清空队列,也省下了很多时间,且思路和上一道题一样,用一个队列模拟队列即可

#include<bits/stdc++.h>
using namespace std;
string f;
int n,i,k;
queue<int>h;
int main(){
	ios::sync_with_stdio(false);
	cin>>n;
	for(i=1;i<=n;i++){
		cin>>f;
		if(f=="1"){
			cin>>k;
			h.push(k);
			continue;
		}
		if(f=="2"){
			if(h.size()==0){
				cout<<"ERR_CANNOT_POP"<<endl;
				continue;
			}
			else {
				h.pop();
				continue;
			}
		}
		if(f=="3"){
			if(h.size()==0){
				cout<<"ERR_CANNOT_QUERY"<<endl;
				continue;
			}
			else{
				cout<<h.front()<<endl;
				continue;
			}
		}
		if(f=="4")
			cout<<h.size()<<endl;
	} 
}

一点话

大家再学新知识点的时候,推荐大家去做一下洛谷上面的相应模板题,这样没有太大的思维难度,也能帮助你熟悉相应操作,难度适中,很适合入门!

今天就讲到这里了,下次再见!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来自八中的小鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值