内容为武汉大学国家网络安全学院2022级大一第三学期“996”实训课程中所做的笔记,仅供个人复习使用,如有侵权请联系本人,将与15个工作日内将博客设置为仅粉丝可见。
队列的演示
略
栈的演示
略
队列和栈
队列:
int q[1000], l = 0, r = 0; // 初始化
q[r++] = x; // 入队
int now = q[l]; // 获取队首
l++; // 出队
q[r++] = y;
printf("%d\n", q[l++]); // 获取队首同时出队
if (l < r) { // 判断是否为空
printf("not empty\n");
}
栈:
int s[100], top = -1;
s[++top] = x; // 入栈
int now = s[top]; // 获取栈顶元素
top--; // 出栈
s[++top] = y;
printf("%d\n", s[top--]); // 获取栈顶同时出栈
if (top >= 0) { // 栈不为空
printf("not empty\n");
}
循环队列:
const int size = 100000;
int q[size], l = 0, r = 0; // 初始化
q[r] = x; r = (r + 1) % size; // 入队
int now = q[l]; // 获取队首
l = (l + 1) % size; // 出队
q[r] = y; r = (r + 1) % size;
printf("%d\n", q[l]); l = (l + 1) % size; // 获取队首同时出队
if (l != r) { // 判断是否为空
printf("not empty\n");
}
字符串栈:
char s[100][1000], top = -1;
scanf("%s", s[++top]); // 入栈
char t[1000];
strcpy(t, s[top]); // 获取栈顶元素
top--; // 出栈
strcpy(s[++top], t);
printf("%s\n", s[top--]); // 获取栈顶同时出栈
if (top >= 0) { // 栈不为空
printf("not empty\n");
}
报数
- 时间限制:1000ms
- 空间限制:131072K
- 语言限制:C语言
有 n 个小朋友做游戏,他们的编号分别是 1,2,3...n。他们按照编号从小到大依次顺时针围成一个圆圈,从第一个小朋友开始从 1 报数,依次按照顺时针方向报数(加一),报 m 的人会离开队伍,然后下一个小朋友会继续从 1 开始报数,直到只剩一个小朋友为止。
输入格式
第一行输入两个整数,n,m。(1≤n,m≤1000)
输出格式
输出最后一个小朋友的编号,占一行。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
10 5
样例输出
3
题解:用队列模拟。
我的答案
#include <stdio.h>
#include <stdlib.h>
#define MAXN 1000
typedef struct {
int data[MAXN];
int front, rear;
} Queue;
void initQueue(Queue *q) {
q->front = q->rear = 0;
}
int isQueueEmpty(Queue *q) {
return q->front == q->rear;
}
void enQueue(Queue *q, int x) {
q->data[q->rear] = x;
q->rear = (q->rear + 1) % MAXN;
}
int deQueue(Queue *q) {
int x = q->data[q->front];
q->front = (q->front + 1) % MAXN;
return x;
}
int main() {
int n, m;
if (scanf("%d%d", &n, &m) != 2) {
fprintf(stderr, "输入错误\n");
exit(1);
}
Queue q;
initQueue(&q);
for (int i = 1; i <= n; i++) {
enQueue(&q, i);
}
int cnt = 0;
while (!isQueueEmpty(&q)) {
int x = deQueue(&q);
cnt++;
if (cnt == m) {
cnt = 0;
} else {
enQueue(&q, x);
}
}
printf("%d\n", q.data[(q.rear - 1 + MAXN) % MAXN]);
return 0;
}
敲7
- 时间限制:1000ms
- 空间限制:131072K
- 语言限制:C语言
有一种酒桌游戏叫做“敲7”,规则是从一个人开始,说出任意数字,其他人会顺序往后报,如果一个数字包含 7,或者是 7 的倍数,那么需要敲打杯子或盘子,不能说出。
现在 n 个人围坐在一个圆桌周围,他们编号从 1 到 n 顺时针排列。从某一人开始报出一个数字,其他人会按照顺时针方向顺序往后报(加一),如果某个人的数字包含 7,或者是 7 的倍数,那么他将退出游戏,下一个人继续接着报,直到剩一个人为止。
输入格式
第一行输入三个整数,n,m,t。n 代表总人数,m 代表从第 m 个人开始报数,他报出的数字是 t。(1≤m≤n≤1000,1≤t≤100)
接下来的 n 行,每一行输入一个字符串,代表这 n 个人的名字,字符串的长度不超过 20。
输出格式
输出剩下的那个人的名字,占一行。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
5 3 20
donglali
nanlali
xilali
beilali
chuanpu
样例输出
chuanpu
题解:队列里储存每个人的名字,先把前 m−1 个人从队首取出放入队尾,然后模拟报数直到队列中只剩下一个人。
我的答案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 1000
typedef struct {
int data[MAXN];
int front, rear;
} Queue;
void initQueue(Queue *q) {
q->front = q->rear = 0;
}
int isQueueEmpty(Queue *q) {
return q->front == q->rear;
}
void enQueue(Queue *q, int x) {
q->data[q->rear] = x;
q->rear = (q->rear + 1) % MAXN;
}
int deQueue(Queue *q) {
int x = q->data[q->front];
q->front = (q->front + 1) % MAXN;
return x;
}
int check(int x) {
if (x % 7 == 0) return 1;
while (x) {
if (x % 10 == 7) return 1;
x /= 10;
}
return 0;
}
char name[MAXN][25];
int main() {
int n, m, t;
scanf("%d%d%d", &n, &m, &t);
for (int i = 1; i <= n; i++) {
scanf("%s", name[i]);
}
Queue q;
initQueue(&q);
for (int i = m; i <= n; i++) {
enQueue(&q, i);
}
for (int i = 1; i < m; i++) {
enQueue(&q, i);
}
while (!isQueueEmpty(&q)) {
int x = deQueue(&q);
if (check(t)) {
} else {
enQueue(&q, x);
}
t++;
}
printf("%s\n", name[q.data[(q.rear - 1 + MAXN) % MAXN]]);
return 0;
}
括号匹配
- 时间限制:1000ms
- 空间限制:131072K
- 语言限制:C语言
蒜头君在纸上写了一个串,只包含'('
和')'
。一个'('
能唯一匹配一个')'
,但是一个匹配的'('
必须出现在')'
之前。请判断蒜头君写的字符串能否括号完全匹配,如果能,输出配对的括号的位置(匹配的括号不可以交叉,只能嵌套)。
输入格式
一行输入一个字符串只含有'('
和')'
,输入的字符串长度不大于 5000050000。
输出格式
如果输入括号不能匹配,输出一行"No"
,否则输出一行"Yes"
,接下里若干行每行输出 22 个整数,用空格隔开,表示所有匹配对的括号的位置(下标从 11 开始)。你可以按照任意顺序输出。
特判说明
本题答案不唯一,符合要求的答案均正确
样例输入1
(())
样例输出1
Yes
1 4
2 3
样例输入2
()()
样例输出2
Yes
1 2
3 4
题解:从左往右扫一遍括号序列,如果遇到一个(
,那把当前下标压入栈中,如果遇到)
,从栈中弹出一个左括号的位置,存入答案中。如果当前栈为空,就说明括号序列不合法。扫完序列后,栈不为空,也说明括号序列不合法。
我的答案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 50000
typedef struct {
int data[MAXN];
int top;
} Stack;
void initStack(Stack *s) {
s->top = -1;
}
int isStackEmpty(Stack *s) {
return s->top == -1;
}
void push(Stack *s, int x) {
s->data[++s->top] = x;
}
int pop(Stack *s) {
return s->data[s->top--];
}
char str[MAXN + 5];
int ans[MAXN][2], cnt;
int main() {
scanf("%s", str + 1);
int n = strlen(str + 1);
Stack s;
initStack(&s);
for (int i = 1; i <= n; i++) {
if (str[i] == '(') {
push(&s, i);
} else {
if (isStackEmpty(&s)) {
printf("No\n");
return 0;
}
int x = pop(&s);
ans[++cnt][0] = x;
ans[cnt][1] = i;
}
}
if (!isStackEmpty(&s)) {
printf("No\n");
return 0;
}
printf("Yes\n");
for (int i = 1; i <= cnt; i++) {
printf("%d %d\n", ans[i][0], ans[i][1]);
}
return 0;
}
网页跳转
- 时间限制:1500ms
- 空间限制:131072K
- 语言限制:C语言
蒜头君每天都在用一款名为“蒜厂浏览器”的软件。在这个浏览器中,一共三种操作:打开页面、回退和前进。它们的功能如下:
- 打开页面:在地址栏中输入网址,并跳转到网址对应的页面;
- 回退:返回到上一次访问的页面;
- 前进:返回到上次回退前的页面,如果上一次操作是打开页面,那么将无法前进。
现在,蒜头君打开浏览器,进行了一系列操作,你需要输出他每次操作后所在页面的网址。
输入格式
第一行输入一个整数 n(0<n≤100000),表示蒜头君的操作次数。
接下来一共 n 行,每行首先输入一个字符串,如果是VISIT
,后面接着输入一个不含有空格和换行的网址(网址长度小于 100),表示蒜头君在浏览器地址栏中输入的网址;如果是BACK
,表示蒜头君点击了回退按钮;如果是FORWARD
,表示蒜头君点击了前进按钮。
输出格式
对于每次操作,如果蒜头君能操作成功,输出蒜头君操作之后的网址,否则输出Ignore
。假设蒜头君输入的所有网址都是合法的。
格式说明
输出时每行末尾的多余空格,不影响答案正确性
样例输入
10
VISIT https://www.jisuanke.com/course/476
VISIT https://www.taobao.com/
BACK
BACK
FORWARD
FORWARD
BACK
VISIT https://www.jisuanke.com/course/429
FORWARD
BACK
样例输出
https://www.jisuanke.com/course/476
https://www.taobao.com/
https://www.jisuanke.com/course/476
Ignore
https://www.taobao.com/
Ignore
https://www.jisuanke.com/course/476
https://www.jisuanke.com/course/429
Ignore
https://www.jisuanke.com/course/476
题解:需要开两个栈,st1
存放当前浏览的记录,st2
存放当前回退的记录。
- 如果是访问操作,清空
st2
,然后把新的网址放入st1
并输出该网址 - 如果是回退操作,只有在
st1
的大小至少为 22 时才能回退。把st1
的栈顶网址取出,放入st2
中,然后输出st1
栈顶的网址 - 如果是前进操作,只有在
st2
不为空时才能前进,弹出st2
的栈顶元素并输出,然后放入st1
中。
我的答案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_URL_LEN 100
#define MAX_N 100000
typedef struct Stack {
char urls[MAX_N][MAX_URL_LEN];
int top;
} Stack;
void stack_init(Stack* stack) {
stack->top = -1;
}
int stack_is_empty(Stack* stack) {
return stack->top == -1;
}
int stack_is_full(Stack* stack) {
return stack->top == MAX_N - 1;
}
void stack_push(Stack* stack, char* url) {
if (!stack_is_full(stack)) {
strcpy(stack->urls[++stack->top], url);
}
}
char* stack_pop(Stack* stack) {
if (!stack_is_empty(stack)) {
return stack->urls[stack->top--];
}
return NULL;
}
char* stack_top(Stack* stack) {
if (!stack_is_empty(stack)) {
return stack->urls[stack->top];
}
return NULL;
}
int main() {
int n;
char operation[10], url[MAX_URL_LEN];
Stack back_stack, forward_stack;
stack_init(&back_stack);
stack_init(&forward_stack);
scanf("%d", &n);
while (n--) {
scanf("%s", operation);
if (strcmp(operation, "VISIT") == 0) {
scanf("%s", url);
stack_push(&back_stack, url);
printf("%s\n", url);
stack_init(&forward_stack);
} else if (strcmp(operation, "BACK") == 0) {
if (back_stack.top < 1) {
printf("Ignore\n");
} else {
stack_push(&forward_stack, stack_pop(&back_stack));
printf("%s\n", stack_top(&back_stack));
}
} else if (strcmp(operation, "FORWARD") == 0) {
if (stack_is_empty(&forward_stack)) {
printf("Ignore\n");
} else {
char *next_url = stack_pop(&forward_stack);
stack_push(&back_stack, next_url);
printf("%s\n", next_url);
}
}
}
return 0;
}