【洛谷B3614】【模板】栈 解题报告

B3614 【模板】栈(传送门)


【模板】栈

题目描述

请你实现一个栈(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! 含有叹号。

刚拿到这个题时,我先不假思索地尝试了最简单的静态数组写法,但是……
看一下数据范围: n n n能到 1 0 6 10^6 106,x能到 2 64 2^{64} 264,说明 x x x要用无符号长整型 u n s i g n e d   l o n g   l o n g unsigned\ long\ long unsigned long long,用静态数组显然会炸掉(RE)。

0分代码 (建议别看)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ull unsigned long long
using namespace std;

const int MAXN = 10007;
typedef struct {
	ull data[MAXN];
	int top;
}SqStack;

inline bool StackEmpty(SqStack& S) {
	return S.top == -1 ? true : false;
}

inline void Push(SqStack& S, ull x) {
	S.data[++S.top] = x;
	return;
}

inline void Pop(SqStack& S) {
	if (StackEmpty(S))printf("Empty\n");
	else S.top--;
	return;
}

inline void Query(SqStack& S) {
	if (StackEmpty(S))printf("Anguei!\n");
	else printf("%llu\n", S.data[S.top]);
	return;
}

inline void Opt() {
	int n;
	scanf("%d", &n);
	ull x;
	char ch;
	SqStack S;
	S.top = -1;
	while (n--) {
		ch = getchar();
		if (ch == 'p') {
			ch = getchar();
			if (ch == 'u') {
				ch = getchar(),ch = getchar();
				scanf(" %llu", &x);
				Push(S, x);
			}
			else if (ch == 'o') {
				ch = getchar(), ch = getchar();
				Pop(S);
			}
		}
		else if (ch == 'q') {
			ch = getchar(), ch = getchar(), ch = getchar(), ch = getchar(), ch = getchar();
			Query(S);
		}
		else if (ch == 's') {
			ch = getchar(), ch = getchar(), ch = getchar(), ch = getchar();
			printf("%d\n", S.top + 1);
		}
	}
	return;
}

int main() {
	int T;
	scanf("%d", &T);
	for (int i = 1; i <= T; ++i)
		Opt();
	return 0;
}

实际上,如果MAXN开到 1 e 6 + 7 1e6+7 1e6+7的话,本地编译都过不了,内存直接爆炸(骗分失败
而且我这里读指令也用了个很“鸡贼”的写法,用 g e t c h a r ( ) getchar() getchar()一个一个读来判断,看起来好像有那么回事,其实跑到最后甚至没法结束输入……
鉴定为太久没打OI导致的,细节都做得很差,痛定思痛,于是我准备用正规的链栈写法来做。
出乎意料的是,一遍就直接AC了,嗯,不错。
具体实现我会在代码的注释里给出讲解,需要的前置知识有:单链表栈的基本概念

满分代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>//输入输出流必备头文件
#define ull unsigned long long//用ull替换unsigned long long让代码更简洁
using namespace std;

typedef struct SNode{
	int len;//记录表长(栈内元素个数)
	ull data;//记录数据元素
	struct SNode* next;
}SNode,* SqStack;//单链表形式定义栈

inline void InitStack(SqStack& S) {//初始化栈
	S = (SNode*)malloc(sizeof(SNode));//分配头结点
	S->next = NULL;
	S->len = 0;//初始表长为0
	return;
}

inline bool StackEmpty(SqStack& S) {//判空
	return S->len == 0 ? true : false;//表长为0则为空栈
}

inline void Push(SqStack& S, ull x) {//入栈
	SNode* p = (SNode*)malloc(sizeof(SNode));//分配新结点
	if (p == NULL)return;//分配失败
	p->data = x;//记录新数据
	p->next = S->next;//将新节点p的后继指向栈顶元素的后继
	S->next = p;//栈顶元素的后继再指向p,完成插入
	S->len++;//表长+1
	return;
}

inline void Pop(SqStack& S) {//出栈
	if (StackEmpty(S))printf("Empty\n");//若表长为0则为空栈,按题意输出“Empty”
	else {
		SNode* p = S->next;//否则,用临时结点p指向栈顶元素
		S->next = p->next;//栈顶元素的后继指向其后继的后继
		free(p);//释放栈顶元素,完成出栈
		S->len--;//表长-1
	}
	return;
}

inline void Query(SqStack& S) {//询问栈顶元素
	if (StackEmpty(S))printf("Anguei!\n");//若表长为0则为空栈,按题意输出“Anguei!”
	else printf("%llu\n", S->next->data);//否则输出栈顶元素数据
	return;
}

int main() {
	int T,n;
	std::cin >> T;//std输入流
	string str;//记录操作字符串
	ull x;
	for (int i = 1; i <= T; ++i) {//T组数据
		std::cin >> n;
		SqStack S;//声明一个栈
		InitStack(S);
		for (int j = 1; j <= n; ++j) {//n次操作
			std::cin >> str;//std输入流,遇空格即停止,这一点比scanf好用
			if (str == "push") {//若为push,则进行入栈操作
				std::cin >> x;
				Push(S, x);
			}
			else if (str == "pop") {//若为pop,则进行出栈操作
				Pop(S);
			}
			else if (str == "query") {//若为query,则进行询问栈顶元素操作
				Query(S);
			}
			else if (str == "size") {//若为size,则输出表长
				printf("%d\n", S->len);
			}
		}
	}
	return 0;
}

所以说,想当然或者投机取巧都是不行的,还是要老老实实、脚踏实地打代码。
感觉写个普及-的题都汗流浃背了,自己代码功力退化的还是很严重啊。
继续加油吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值