泛型栈
本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 60 课,共 61 课。
挑战
简单栈是一种基础数据结构,遵循后进先出(LIFO)原则:最后添加的元素最先移除。可以把它想象成一摞盘子:从顶部放入,也从顶部取出。
让我们来构建一个通用栈:一种使用 void* 指针存储任意类型数据的灵活数据结构。你的栈将遵循后进先出原则,并包含所有必要的操作。
你将把代码分成 3 个文件:
stack.h:定义Stack结构体,包含 3 个成员:用于存放元素的void**数组、表示栈顶索引(下一个空闲位置)的int,以及表示容量的int。声明用于创建栈(接收一个容量)、压入元素、弹出元素、查看栈顶元素、检查栈是否为空,以及释放栈的函数原型。stack.c:实现通用栈:create_stack:在堆上分配一个 Stack,按给定容量分配元素数组,将 top 初始化为 0,并返回指针push:如果还有空间(即 top 小于 capacity),就将元素添加到栈顶pop:移除并返回栈顶元素;如果栈为空,则返回NULLpeek:返回栈顶元素但不移除;如果栈为空,则返回NULLis_empty:如果栈中没有元素,则返回 1;否则返回 0free_stack:先释放元素数组,再释放 Stack 结构体本身
main.c:读取要执行的操作数量。然后对每个操作读取一条命令:push后跟一个整数值、pop或peek。创建一个容量为 10 的栈。对于push,在堆上分配一个整数并压入它的指针。对于pop,取出元素,打印它的值,并释放该整数。对于peek,打印值但不移除元素。如果在空栈上调用pop或peek,则打印empty。执行完所有操作后,释放剩余元素和栈。
程序将接收以下输入:
- 操作数量
- 每行一条操作(
push X、pop或peek)
输入依次为 5、push 10、push 20、peek、pop、pop 时的输出示例:
20
20
10输入依次为 3、pop、push 42、peek 时的输出示例:
empty
42输入依次为 4、push 5、push 15、pop、pop 时的输出示例:
15
5请记住,你的栈存储的是 void* 指针:实际数据由调用者负责分配和释放。弹出元素时,将返回的 void* 转换回 int*,以访问其值。使用 <string.h> 中的 strcmp 比较命令字符串。
亲手试试
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
int main() {
int n;
scanf("%d", &n);
// TODO: 创建一个容量为 10 的栈
// TODO: 处理每个操作
for (int i = 0; i < n; i++) {
char command[10];
scanf("%s", command);
if (strcmp(command, "push") == 0) {
int value;
scanf("%d", &value);
// TODO: 在堆上为一个整数分配内存,并将其指针压入栈
}
else if (strcmp(command, "pop") == 0) {
// TODO: 弹出栈顶元素
// 如果不是 NULL,打印值并释放该整数
// 如果是 NULL(栈为空),打印 "empty"
}
else if (strcmp(command, "peek") == 0) {
// TODO: 查看栈顶元素
// 如果不是 NULL,打印值(不要移除或释放)
// 如果是 NULL(栈为空),打印 "empty"
}
}
// TODO: 释放栈中剩余的所有元素
// TODO: 释放栈本身
return 0;
}
面向对象编程中的所有课
自己练习: C 在线编译器