week3线性数据结构

T1:luogu:P3613

超市里有 n(1\le n\le10^5)n(1≤n≤105) 个寄包柜。每个寄包柜格子数量不一,第 ii 个寄包柜有 a_i(1\le a_i\le10^5)ai​(1≤ai​≤105) 个格子,不过我们并不知道各个 a_iai​ 的值。对于每个寄包柜,格子编号从 1 开始,一直到 a_iai​。现在有 q(1 \le q\le10^5)q(1≤q≤105) 次操作:

  • 1 i j k:在第 ii 个柜子的第 jj 个格子存入物品 k(0\le k\le 10^9)k(0≤k≤109)。当 k=0k=0 时说明清空该格子。
  • 2 i j:查询第 ii 个柜子的第 jj 个格子中的物品是什么,保证查询的柜子有存过东西。

已知超市里共计不会超过 10^7107 个寄包格子,a_iai​ 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然也有可能某些寄包柜中一个格子都没有。

输入格式

第一行 2 个整数 nn 和 qq,寄包柜个数和询问次数。

接下来 qq 个整数,表示一次操作。

输出格式

对于查询操作时,输出答案,以换行隔开。

输入输出样例

输入 #1复制

5 4
1 3 10000 118014
1 1 1 1
2 3 10000
2 1 1

输出 #1复制

118014
1

思路:既然学了一点数据结构,那就浅浅的用map来做,读入寄包柜个数n和询问次数q后,再读入依次读入操作x(1或0),以及对应的柜子(gui),格子(ge),如果x==1,继续读入k,将对应的柜子中格子,改为k;如果x==0,输出对应的查询结果

主要是用map的一些基本操作:

  • map<key,elem> 名称;(默认以less<>排序为标准)
  • map<key,   elem,op> 名称;(以op排序为标准)

首先map是stl内置的一个容器,健-值对的集合(不允许重复的元素),其中key相当于一个身份证,通过这个身份证,可以查询到你的种种信息,当然map本身也可以作为数据类型本身(类似vector实现二维数组)

然后是它的一些操作(时间复杂度为log2N)

1:map的大小:map.size();

2:判断map是否为空:map.empty(),若为空返回true,反之为false

函数原型:bool empty ()

3:遍历map:map不支持元素直接存取,需要通过迭代器实现

函数:

  • begin()【指向第一个元素】
  • end()【指向最后一个元素的下一个元素】
  • rbegin()【指向最后一个元素】
  • rend()【指向第一个元素】,加个r相当于反向迭代。

4:map元素的插入和删除:

  1. 插入:insert()函数,分为三种形式:
  • 第一种:map.insert(elem)将元素插入到map的末尾
  • 第二种:map.insert (iterator it,elem)将元素elem插入到迭代器it之前
  • 第三种:map.insert(first,last)将迭代器(first,last)指定范围的元素插入到map
  1. 删除:erase();

全部删除:clear();

#include<bits/stdc++.h>
using namespace std;
map<int,map<int,int> > v;
int n,q,gui,ge,w;
int main()
{
	
	cin>>n>>q;
	for(int i=1;i<=q;i++)
	{
		int x;
		cin>>x>>gui>>ge;
		if(x==1){
		    cin>>w;
			v[gui][ge]=w;        
		}
		else if(x==2){
			cout<<v[gui][ge]<<endl;
		}
	}
	return 0;
}

T2:括号序列

定义如下规则:

  1. 空串是「平衡括号序列」
  2. 若字符串 SS 是「平衡括号序列」,那么 \texttt{[}S\texttt][S] 和 \texttt{(}S\texttt)(S) 也都是「平衡括号序列」
  3. 若字符串 AA 和 BB 都是「平衡括号序列」,那么 ABAB(两字符串拼接起来)也是「平衡括号序列」。

例如,下面的字符串都是平衡括号序列:

()[](())([])()[]()[()]

而以下几个则不是:

([])(())([()

现在,给定一个仅由 ()[]构成的字符串 ss,请你按照如下的方式给字符串中每个字符配对:

  1. 从左到右扫描整个字符串。
  2. 对于当前的字符,如果它是一个右括号,考察它与它左侧离它最近未匹配的的左括号。如果该括号与之对应(即小括号匹配小括号,中括号匹配中括号),则将二者配对。如果左侧未匹配的左括号不存在或与之不对应,则其配对失败。

配对结束后,对于 ss 中全部未配对的括号,请你在其旁边添加一个字符,使得该括号和新加的括号匹配。

输入格式

输入只有一行一个字符串,表示 ss。

输出格式

输出一行一个字符串表示你的答案。

输入输出样例

输入 #1复制

([()

输出 #1复制

()[]()

思路:用一个int类型的栈储存对应左括号的序号,当右括号来临,且对应的左括号,左括号的序列恰好在栈顶的位置,我们将这两个括号分别标记为1,代表已经匹配,在输出时候就无需额外操作,直接输出,对于未匹配的括号,我们在输出时输出完整的一对括号。

#include<bits/stdc++.h>
using namespace std;
string s;
stack <int> sta;
bool match[105];
int main()
{
	cin>>s;
	int n=s.length();
	for(int i=0;i<n;i++){
		if(s[i]==')')//如果为右小括号,寻找栈顶是否为左小括号 
		{
			if(sta.empty())continue;//如果栈为空,显然不能匹配 ,标记为false
			if(s[sta.top()]=='(')match[i]=1,match[sta.top()]=1,sta.pop();//匹配成功,将栈顶的这个左括号标记为ture,移除栈 
		}
		else if(s[i]==']')//如果为右中括号,寻找栈顶是否为右中括号 
		{
			if(sta.empty())continue;//如果栈为空,显然不能匹配 ,标记为false
			if(s[sta.top()]=='[')match[i]=1,match[sta.top()]=1,sta.pop();
		}
		else sta.push(i);
	}
	for(int i=0;i<n;i++)
	{
		if(match[i])cout<<s[i];//如果已经匹配了直接输出 
		else{//没有匹配输出对应括号 
			if(s[i]==')'||s[i]=='(')cout<<"()";
			if(s[i]=='['||s[i]==']')cout<<"[]";
		}
	}
	return 0;
}

T3:后缀表达式

所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。

如:\texttt{3*(5-2)+7}3*(5-2)+7 对应的后缀表达式为:\texttt{3.5.2.-*7.+@}3.5.2.-*7.+@。在该式中,@ 为表达式的结束符号。. 为操作数的结束符号。

输入格式

输入一行一个字符串 ss,表示后缀表达式。

输出格式

输出一个整数,表示表达式的值。

输入输出样例

输入 #1复制

3.5.2.-*7.+@

输出 #1复制

16

思路:同样的,我们用一个int类型的栈储存,输入的数字,当遇到运算符,依次取出并删除栈顶B,及栈顶下面的一个元素A,然后A operate

B,然后将操作的结果放置于栈顶。

 #include<bits/stdc++.h>
 using namespace std;
 stack <int> sta;
 string s; 
 int main()
 {
 	cin>>s;
 	int n=s.length(),t=0;
 	for(int i=0;i<n;i++){
 		//cout<<"读入的字符为"<<s[i]<<' ';
 		if(s[i]>='0'&&s[i]<='9')//如果输入的是数字
		{
			t*=10;
			t+=(s[i]-'0');
		}
		else if(s[i]=='.'){
			//cout<<"入栈的数字"<<t<<endl; 
			sta.push(t);//完成对这个数字的读入 
			t=0;//t清为0 
		} //下面对栈内的数字进行操作 
		else if(s[i]=='-'){
			int b,a,T;
			b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
			a=sta.top();sta.pop();
			T=a-b;sta.push(T);
		}
		else if(s[i]=='+')
		{
			int b,a,T;
			b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
			a=sta.top();sta.pop();
			T=a+b;sta.push(T);
		} 
		else if(s[i]=='*'){
			int b,a,T;
			b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
			a=sta.top();sta.pop();
			T=a*b;sta.push(T);
		}
		else if(s[i]=='/')
		{
			int b,a,T;
			b=sta.top();sta.pop();//取出栈顶的元素并删除栈顶元素
			a=sta.top();sta.pop();
			T=a/b;sta.push(T);
		}
		else if(s[i]=='@')break;
	 }
	 cout<<sta.top();
	 return 0;
 }

T4;队列安排

一个学校里老师要将班上 NN 个同学排成一列,同学被编号为 1\sim N1∼N,他采取如下的方法:

  1. 先将 11 号同学安排进队列,这时队列中只有他一个人;

  2. 2-N2−N 号同学依次入列,编号为 ii 的同学入列方式为:老师指定编号为 ii 的同学站在编号为 1\sim(i-1)1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;

  3. 从队列中去掉 M(M<N)M(M<N) 个同学,其他同学位置顺序不变。

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。

输入格式

第 11 行为一个正整数 NN,表示了有 NN 个同学。

第 2\sim N2∼N行,第 ii 行包含两个整数 k,pk,p,其中 kk 为小于 ii 的正整数,pp 为 00 或者 11。若 pp 为00,则表示将 ii 号同学插入到 kk 号同学的左边,pp 为 11 则表示插入到右边。

第 N+1N+1 行为一个正整数 MM,表示去掉的同学数目。

接下来 MM 行,每行一个正整数 xx,表示将 xx 号同学从队列中移去,如果 xx 号同学已经不在队列中则忽略这一条指令。

输出格式

11 行,包含最多 NN 个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。

输入输出样例

输入 #1复制

4
1 0
2 1
1 0
2
3
3

输出 #1复制

2 4 1

说明/提示

样例解释:

将同学 22 插入至同学 11 左边,此时队列为:

2 1

将同学 33 插入至同学 22 右边,此时队列为:

2 3 1

将同学 44 插入至同学 11 左边,此时队列为:

2 3 4 1

将同学 33 从队列中移出,此时队列为:

2 4 1

同学 33 已经不在队列中,忽略最后一条指令

最终队列:

2 4 1

思路:这道题是一个双链表的题目,我采用的是用数组模拟双链表的操作,然后用数组的第0号的R储存链表的开头,对于删除操作,将链表两端的R和L全部都设置为-1,对于输出到末尾元素(只将R端标记为-1,就可以结束输出循环)

#include<bits/stdc++.h>
using namespace std;
struct node{
	int R,L;
}le[100005];
int n,m;
int main()
{
	le[0].R=1;
	le[1].L=0;le[1].R=-1;
	cin>>n;
	for(int i=2;i<=n;i++){
		int k,p;
		cin>>k>>p;
		if(p)
        {
            le[i].L = k;
            le[le[k].R].L = i;
            le[i].R = le[k].R;
            le[k].R = i;
        }
		else
        {
            le[i].R = k;
            le[le[k].L].R = i;
            le[i].L = le[k].L;
            le[k].L = i;
        }
        //cout<<"0后面链接的数为"<<le[0].R<<endl;
	}//完成插入操作
	//cout<<"未删数时"<<endl;
	//for(int i=1;i<=n;i++)cout<<le[i].L<<" "<<i<<' '<<le[i].R<<endl;
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		int x;
		cin>>x;
		//for(int i=1;i<=n;i++)cout<<le[i].L<<" "<<i<<' '<<le[i].R<<endl;
		if(le[x].L==-1&&le[x].R==-1)continue;
		le[le[x].L].R = le[x].R;
        le[le[x].R].L = le[x].L;
        le[x].R = le[x].L = -1;
	}
	int fs=le[0].R;
	while(fs != -1)
    {
        cout<<fs<<' ';
        fs= le[fs].R;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值