week3小总结

这周真是魔幻现实,科技论文、入党、团委一堆事铺面而来,昨晚还发烧了(差点以为要被隔离了 )。这周的队内练习题都还没打完(这周才知道原来我们是全校最多课的,没有之一~ ),只能先把写了的做做总结了。这周主要学习的是各种基本的数据结构,比如栈,队列什么的。

1.栈

栈,又名堆栈,是一种运算受限制的线性表,限制是:仅仅允许从表的一段插入和删除运算。这一段称为栈顶,把另一端称为栈底。向一个栈插入新元素又称为进栈、入栈和压栈。它是把新元素放到栈顶元素上面,使之称为新的栈顶元素;从一个栈删除元素又称作出栈或者退栈,它是将栈顶元素删除,使其相邻的元素称为新的栈顶元素。

栈的相关概念:

栈顶与栈底:允许元素插入与删除的一端称为栈顶,另一端称为栈底。
压栈:栈的插入操作,叫做进栈,也称压栈、入栈。
弹栈:栈的删除操作,也叫做出栈。

栈的常用操作
弹栈,通常命名为pop
压栈,通常命名为push
求栈的大小
判断栈是否为空
获取栈顶元素的值

栈的存储结构
栈能够以数组或链表(单向链表、双向链表或循环链表)作为底层数据结构。
(虽然本juruo一般用数组模拟栈)
注意一点:基于数组的栈——以数组为底层数据结构时,通常以数组头为栈底,数组头到数组尾为栈顶的生长方向,但是基于单链表的栈——以链表为底层的数据结构时,以链表头为栈顶,便于节点的插入与删除,压栈产生的新节点将一直出现在链表的头部。

STL实现

#include<stack>    //必备头文件 
stack<int>s;       //建立栈 
s.empty();         //如果栈为空则返回true, 否则返回false;
s.size();          //返回栈中元素的个数
s.top();           //返回栈顶元素, 但不删除该元素
s.pop();           //弹出栈顶元素, 但不返回其值
s.push();          //将元素压入栈顶

手动模拟实现
直接在例题中体现

例题1
As the new term comes, the Ignatius Train Station is very busy nowadays. A lot of student want to get back to school by train(because the trains in the Ignatius Train Station is the fastest all over the world v). But here comes a problem, there is only one railway where all the trains stop. So all the trains come in from one side and get out from the other side. For this problem, if train A gets into the railway first, and then train B gets into the railway before train A leaves, train A can’t leave until train B leaves. The pictures below figure out the problem. Now the problem for you is, there are at most 9 trains in the station, all the trains has an ID(numbered from 1 to n), the trains get into the railway in an order O1, your task is to determine whether the trains can get out in an order O2.

Input
The input contains several test cases. Each test case consists of an integer, the number of trains, and two strings, the order of the trains come in:O1, and the order of the trains leave:O2. The input is terminated by the end of file. More details in the Sample Input.
Output
The output contains a string “No.” if you can’t exchange O2 to O1, or you should output a line contains “Yes.”, and then output your way in exchanging the order(you should output “in” for a train getting into the railway, and “out” for a train getting out of the railway). Print a line contains “FINISH” after each test case. More details in the Sample Output.
Sample Input
3 123 321
3 123 312
Sample Output
Yes.
in
in
in
out
out
out
FINISH
No.
FINISH

For the first Sample Input, we let train 1 get in, then train 2 and train 3.
So now train 3 is at the top of the railway, so train 3 can leave first, then train 2 and train 1.
In the second Sample input, we should let train 3 leave first, so we have to let train 1 get in, then train 2 and train 3.
Now we can let train 3 leave.
But after that we can’t let train 1 leave before train 2, because train 2 is at the top of the railway at the moment.
So we output “No.”.

题意大概就是问列车以给的的顺序依次进车站,然后看能否
让车出去的顺序是给定的那样。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n;
int tot,s[100000],ans[100100],sum,be[100000],en[100000];
char a[10000],b[100000];
void push(int k)//进栈
{
	tot++;
	s[tot] = k;
}
int main()
{
	while(cin>>n>>a>>b)
	{
		tot = 0;sum = 0;
		memset(ans,0,sizeof(0));
		for(int i=n;i>=1;i--)
		{
			be[i] = a[i-1] - '0';
		}
		for(int i=n;i>=1;i--)
		{
			en[i] = b[i-1] - '0';
		}
		int t = 0,flag = 1;
		for(int i=1;i<=n;i++)
		{
			push( be[i] );
			sum++;
			ans[sum] = 1;
			while(s[tot] == en[flag] && tot>=1)
			{
				ans[++sum] = 2;
				flag++;
				tot--;
			}
		}
		if(sum != 2*n)
		{
			printf("No.\n");
		}
		else 
		{
			printf("Yes.\n");
			for(int i=1;i<=sum;i++)
			{
				if(ans[i]==1) printf("in\n");
				else printf("out\n");
			}
		}
		n--;
		printf("FINISH\n");
	}
	return 0;
}

例题2
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
Input
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
Output
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
Sample Input
1 + 2
4 + 2 * 5 - 7 / 11
0
Sample Output
3.00
13.36

显然题目给的是计算一个中缀表达式的最后结果,基本思想是两个栈,一个存数字一个存符号,然后给运算符加上优先级,扫一遍的时候数字入栈,遇到乘法和除法直接先计算了,加法和减法先把运算符入栈,最后再处理。但是,我们可以省去存运算符的栈,在处理数字入栈时候直接处理一下符号,乘法和除法先把栈顶数字弹出来运算,加法直接数字进栈,减法加个负号再入栈。

PS:这里用的getline函数值得说一说
虽然c++可以使用 cin 和 >> 运算符来输入字符串,但它可能会导致一些需要注意的问题。当 cin 读取数据时,它会传递并忽略任何前导白色空格字符(空格、制表符或换行符)。一旦它接触到第一个非空格字符即开始阅读,当它读取到下一个空白字符时它将停止读取。为了解决这个问题,可以使用一个叫做 getline 的 C++ 函数。此函数可读取整行,包括前导和嵌入的空格,并将其存储在字符串对象中。
在C++中本质上有两种getline函数:

第一种:在头文件中,是iostream类的成员函数。

第二种:在头文件中,是普通函数。
第一种: 在中的getline()函数有两种重载形式:

#include <string>
using namespace std;

string s;
getline(cin, s);

#include <cstdio>
#include <iostream>
#include<string>
#include <cstring>
using namespace std;
double str[100000],t,ans;
string a;
char symbol;
int tot = 0;
int main()
{
//	freopen("in.txt","r",stdin);
	int n;
	while (1)
	{
		getline(cin, a);
		if(a=="0") break;
		tot = 0;
		int len = a.size();
		for(int j=len;j<=len+10;j++) a[j]='.'; 
		for(int i=0;;)
		{
			t = 0;
			if(tot != 0)
			{
				symbol = a[i];
				i += 2;
			}
			while(a[i]<='9'&&a[i]>='0')
			{
				t *= 10;
				t += (a[i] - '0');
				i++;
			}
			i--;
			i+=2;
			if(tot==0)
			{
				tot++;
				str[tot] = t;
				continue;
			}
			if(symbol=='+')
			{
				tot++;
				str[tot] = t;
			}
			else if(symbol=='-')
			{
				tot++;
				str[tot] = -t;
			}
			else if(symbol=='*')
			{
				str[tot] *= t;
			}
			else if(symbol=='/')
			{
				str[tot] /= t;
			}
			
			if(a[i] == '.') break;
		}
		for(int i=1;i<=tot;i++)
		{
			ans += str[i];
		}
		printf("%.2lf\n",ans);
		ans = 0;
		memset(str,0,sizeof(str));
	}
	return 0;
}

例题3
Little Bobby Roberts (son of Big Bob, of Problem G) plays this solitaire memory game called Flipper. He starts with n cards, numbered 1 through n, and lays them out in a row with the cards in order left-to-right. (Card 1 is on the far left; card n is on the far right.) Some cards are face up and some are face down. Bobby then performs n - 1 flips — either right flips or left flips. In a right flip he takes the pile to the far right and flips it over onto the card to its immediate left. For example, if the rightmost pile has cards A, B, C (from top to bottom) and card D is to the immediate left, then flipping the pile over onto card D would result in a pile of 4 cards: C, B, A, D (from top to bottom). A left flip is analogous.

The very last flip performed will result in one pile of cards — some face up, some face down. For example, suppose Bobby deals out 5 cards (numbered 1 through 5) with cards 1 through 3 initially face up and cards 4 and 5 initially face down. If Bobby performs 2 right flips, then 2 left flips, the pile will be (from top to bottom) a face down 2, a face up 1, a face up 4, a face down 5, and a face up 3.

Now Bobby is very sharp and you can ask him what card is in any position and he can tell you!!! You will write a program that matches Bobby’s amazing feat.
Input
Each test case will consist of 4 lines. The first line will be a positive integer n (2 ≤ n ≤ 100) which is the number of cards laid out. The second line will be a string of n characters. A character U indicates the corresponding card is dealt face up and a character D indicates the card is face down. The third line is a string of n - 1 characters indicating the order of the flips Bobby performs. Each character is either R, indicating a right flip, or L, indicating a left flip. The fourth line is of the form m q1 q2 . . . qm, where m is a positive integer and 1 ≤ qi ≤ n. Each qi is a query on a position of a card in the pile (1 being the top card, n being the bottom card). A line containing 0 indicates end of input.
Output
Each test case should generate m + 1 lines of output. The first line is of the form
Pile t
where t is the number of the test case (starting at 1). Each of the next m lines should be of the form
Card qi is a face up k.
or
Card qi is a face down k.
accordingly, for i = 1, …,m, where k is the number of the card.
For instance, in the above example with 5 cards, if qi = 3, then the answer would be
Card 3 is a face up 4.
Sample Input
5
UUUDD
RRLL
5 1 2 3 4 5
10
UUDDUUDDUU
LLLRRRLRL
4 3 7 6 1
0
Sample Output
Pile 1
Card 1 is a face down 2.
Card 2 is a face up 1.
Card 3 is a face up 4.
Card 4 is a face down 5.
Card 5 is a face up 3.
Pile 2
Card 3 is a face down 1.
Card 7 is a face down 9.
Card 6 is a face up 7.
Card 1 is a face down 5.

题意大概是U朝上,D朝下,R表示right flipper,L表示left flipper,right flipper意思是,右边的最后一落,翻边,盖到它相邻左边的那一摞上。左翻同理。其中翻的时候顺序刚好颠倒很符合栈的操作。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int tot[110],n,m,l,r,q,sum=0;
struct node
{
	int num,pd;
}a[110][110];
char k;
int main()
{
//	freopen("in.txt","r",stdin);
	while(scanf("%d",&n))
	{
		sum++;
		memset(tot,0,sizeof(tot));
		l=1;
		r=n;
		if(n==0) break;
		for(int i=1;i<=n;i++)
		{
			tot[i] = 1;
			a[i][1].num = i;
			cin>>k;
			if(k=='U') a[i][1].pd = 0;
			else a[i][1].pd = 1;
		}
		for(int i=1;i<=n-1;i++)
		{
			cin>>k;
			if(k=='R')
			{
				for(int j=tot[ r ];j>=1;j--)
				{
					tot[r-1]++;
					a[r][j].pd = ( a[r][j].pd + 1 ) % 2;
					a[r-1][ tot[r-1] ] = a[r][j];
				}
				r--;
			}
			
			if(k=='L')
			{
				for(int j=tot[ l ];j>=1;j--)
				{
					tot[l+1]++;
					a[l][j].pd = ( a[l][j].pd + 1 ) % 2;
					a[l+1][ tot[l+1] ] = a[l][j];
				}
				l++;
			}
		}
		
		scanf("%d",&m);
		printf("Pile %d\n",sum);
		for(int i=1;i<=m;i++)
		{
			scanf("%d",&q);
			int t = tot[r] - q + 1;
			
			if(a[r][t].pd==0)
			printf("Card %d is a face up %d.\n",q,a[r][t].num);
			else printf("Card %d is a face down %d.\n",q,a[r][t].num);
		}
		
	}
	return 0;
}

.

2. 队列

队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表.
队列是一种先进先出(First in First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。一些基本的描述我在查资料的时候我找到了一个还不错的 大姥写的博客,可看。
一个大姥的博客( 点击即可)

优先队列
先上一个漫画版详解
漫画详解(点击即可)
其实这个优先队列类似于就是大根堆和小根堆。

和队列基本操作相同:
top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
pop 弹出队头元素 swap 交换内容
定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆

单调队列
单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。在操作时候只要注意维护一个单调性即可。

例题
题目描述
有一个长为 nn 的序列 aa,以及一个大小为 kk 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

输入格式
输入一共有两行,第一行有两个正整数 n,kn,k。 第二行 nn 个整数,表示序列 aa

输出格式
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值

输入
5
1 4 2 3 5
输出
2 5 4 5 0

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
struct node
{
	int x,y;
}v[1000001];
int n,m,minn[1000001],maxx[1000001];
int a[1000001];

void getmin()
{
	int head=1,tail=0;
	for(int i=1;i<m;i++)
	{
		while(v[tail].x >= a[i] && head <= tail) tail--;
		v[++tail].x=a[i]; v[tail].y=i;
	}
	for(int i=m;i<=n;i++)
	{
		while(v[tail].x >= a[i] && head <= tail) tail--;
		v[++tail].x=a[i];v[tail].y=i;
		while(v[head].y < i-m+1) head++;
		minn[i-m+1]=v[head].x;
	}
}
void getmax()
{
	int head=1;
	int tail=0;
	for(int i=1;i<m;i++)
	{
		while(v[tail].x<=a[i]&&head<=tail) tail--;
		v[++tail].x=a[i]; v[tail].y=i;
	}
	for(int i=m;i<=n;i++)
	{
		while(v[tail].x<=a[i]&&head<=tail) tail--;
		v[++tail].x=a[i];v[tail].y=i;
		while(v[head].y<i-m+1) head++;
		maxx[i-m+1]=v[head].x;
	}
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	getmin();
	getmax();
	for(int i=1;i<=n-m+1;i++)
	{
		printf("%d ",minn[i]);
	}
	cout<<endl;
	for(int i=1;i<=n-m+1;i++)
	{
		printf("%d ",maxx[i]);
	}
	return 0;
}

(快12点了,明天再来把拓展网络流写一写…不咕不咕)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值