顺序栈的基本操作
实验目的
通过该实验,让学生掌握栈的相关基本概念,认识栈是插入和删除集中在一端进行的线性结构,掌握栈的“先进后出”操作特点。栈在进行各类操作时,栈底指针固定不动,掌握栈空、栈满的判断条件。
实验内容
(1)用顺序存储结构,实现教材定义的栈的基本操作。
(2)提供数制转换功能,将输入的十进制整数转换成二进制。
参考界面
验收/测试用例
通过菜单调用各个操作,测试点:
- 没有初始化前进行其他操作,程序是否能控制住。
- 初始化一个栈。
- 判栈空,屏幕显示栈为空。
- 3个数入栈, 1、2、3。
- 栈长度,屏幕输出3。
- 取栈顶元素,再判栈空,然后再判栈长度。
- 出栈,再判栈长度。
- 销毁栈,再做其他操作,判断程序是否能控制。
- 数制转换,输入:8,输出:1000。
参考代码
//From:TengMMVP
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 100 // 定义栈的最大容量
typedef int SElemType; // 假设栈元素类型为int
typedef struct {
SElemType *base; // 栈底指针
SElemType *top; // 栈顶指针
int stacksize; // 当前已分配的存储空间
} SqStack;
// 初始化顺序栈
void InitStack(SqStack *s) {
// 动态分配栈的存储空间,大小为MAXSIZE个SElemType元素
s->base = (SElemType *)malloc(MAXSIZE * sizeof(SElemType));
// 如果内存分配失败,则程序退出
if (!s->base) exit(0);
// 初始化栈顶指针,指向栈底(即空栈状态)
s->top = s->base;
// 设置栈的最大容量为MAXSIZE
s->stacksize = MAXSIZE;
// 输出栈成功创建的信息
printf("顺序栈已成功创建。\n");
}
// 判断顺序栈是否为空
int StackEmpty(SqStack *s) {
// 若栈顶指针等于栈底指针,则说明栈为空
return s->top == s->base;
}
// 清空顺序栈
void ClearStack(SqStack *s) {
// 将栈顶指针重置为栈底,实现栈的清空
s->top = s->base;
// 打印提示信息,告知用户顺序栈已经被清空
printf("顺序栈已清空。\n");
}
// 销毁顺序栈
void DestroyStack(SqStack *s) {
// 释放栈的存储空间
free(s->base);
// 将栈底指针设置为NULL,表示该栈已经不再指向任何有效的内存空间
s->base = NULL;
// 将栈顶指针设置为NULL,表示栈顶无元素
s->top = NULL;
// 将栈的大小设置为0,表示栈为空
s->stacksize = 0;
// 输出提示信息,告知用户顺序栈已经被销毁
printf("顺序栈已销毁。\n");
}
// 返回顺序栈长度
int StackLength(SqStack *s) {
return s->top - s->base;
}
// 返回栈顶元素
int GetTop(SqStack *s, SElemType *item) {
// 首先检查栈是否为空
if (StackEmpty(s)) {
// 如果栈为空,则打印错误信息,并返回0表示失败
printf("顺序栈为空,无法取得栈顶元素!\n");
return 0;
}
// 栈不为空,则将栈顶元素赋值给item指针指向的内存
*item = *(s->top - 1);
// 返回1表示成功取得栈顶元素
return 1;
}
// 入栈操作
int Push(SqStack *s, SElemType item) {
// 检查栈是否已满
if (s->top - s->base >= s->stacksize) {
// 如果栈满,则尝试扩展栈空间
SElemType *newBase = (SElemType *)realloc(s->base, (s->stacksize + MAXSIZE) * sizeof(SElemType));
// 如果内存重新分配失败,则退出程序
if (!newBase) exit(0);
// 更新栈底指针
s->base = newBase;
// 更新栈顶指针到新的栈空间末尾
s->top = s->base + s->stacksize;
// 更新栈的大小
s->stacksize += MAXSIZE;
}
// 将新元素压入栈,并移动栈顶指针
*(s->top++) = item;
// 返回成功标志
return 1;
}
// 出栈操作
int Pop(SqStack *s, SElemType *item) {
// 判断栈是否为空
if (StackEmpty(s)) {
// 如果栈为空,则打印错误信息,并返回0表示出栈失败
printf("顺序栈为空,无法出栈!\n");
return 0;
}
// 将栈顶元素通过指针item返回,并将栈顶指针下移,实现出栈操作
*item = *(--s->top);
// 出栈成功,返回1
return 1;
}
// 打印栈内所有元素
void PrintStack(SqStack *s) {
// 如果栈为空,则打印提示信息并返回
if (StackEmpty(s)) {
printf("顺序栈为空。\n");
return;
}
// 打印栈内元素
printf("顺序栈中的元素为:");
// 遍历栈,从栈底到栈顶前一个元素
for (SElemType *i = s->base; i < s->top; i++) {
// 打印每个元素的值
printf("%d ", *i);
}
printf("\n");
}
// 创建并输入顺序栈元素
void CreateStack(SqStack *s) {
// 检查s->base是否已经分配内存,如果是则释放
if (s->base != NULL) {
free(s->base);
}
s->base = (SElemType *)malloc(MAXSIZE * sizeof(SElemType));
if (!s->base) {
printf("顺序栈内存分配失败!\n");
exit(EXIT_FAILURE);
}
s->top = s->base;
s->stacksize = MAXSIZE;
printf("请输入顺序栈的元素个数(最大%d):", MAXSIZE);
int n, item;
if (scanf("%d", &n) != 1 || n <= 0 || n > MAXSIZE) {
printf("无效的顺序栈元素个数。\n");
return;
}
printf("请依次输入顺序栈的元素:");
for (int i = 0; i < n; i++) {
if (scanf("%d", &item) != 1) {
printf("读取元素失败!\n");
return;
}
Push(s, item);
}
printf("创建并输入顺序栈元素操作成功。\n");
}
// 十进制转二进制并使用栈存储
void DecToBin(SqStack *s, int num) {
SElemType temp,item;
temp=num;
s->top = s->base; // 清空栈,准备存储二进制数字
while (num > 0) {
Push(s, num % 2);
num /= 2;
}
printf("%d的二进制形式为:",temp);
while (!StackEmpty(s)) {
Pop(s, &item);
printf("%d", item);
}
printf("\n");
}
//From:TengMMVP
// 主函数
int main() {
SqStack s; // 预定义顺序栈
int quit = 0, item, num;
bool isInitialized = false, isDestroyed;
while (!quit) {
printf("\n********************栈的操作********************\n");
printf("1. 初始化顺序栈 2. 销毁顺序栈\n");
printf("3. 清空顺序栈 4. 判断顺序栈是否为空\n");
printf("5. 返回顺序栈长度 6. 返回栈顶元素\n");
printf("7. 插入新栈顶元素 8. 删除栈顶元素并返回其值\n");
printf("9. 输出栈内元素 10.创建并输入顺序栈元素\n");
printf("11.十进制转二进制 12.退出程序\n");
printf("************************************************\n");
printf("请输入操作码:");
int choice, operationResult;
scanf("%d", &choice); // 读取操作码
switch (choice) {
case 1: // 初始化顺序栈
InitStack(&s); //调用初始化函数进行顺序栈的初始化
isInitialized = true; // 初始化标志设置为true
isDestroyed = false; // 销毁标志设置为false
break;
case 2: // 销毁顺序栈
if(isInitialized&&!isDestroyed) {
DestroyStack(&s); //调用销毁函数进行顺序栈的销毁
isDestroyed = true; // 销毁标志设置为true
} else {
printf("顺序栈未初始化或已经被销毁,无法进行销毁操作!\n");
}
break;
case 3: // 清空顺序栈
if(isInitialized&&!isDestroyed) {
ClearStack(&s); //调用清空函数进行顺序栈的清空
} else {
printf("顺序栈未初始化或已经被销毁,无法进行清空操作!\n");
}
break;
case 4: // 判断顺序栈是否为空
if(isInitialized&&!isDestroyed) {
// 调用判空函数,返回判断结果
operationResult = StackEmpty(&s);
printf("顺序栈%s为空。\n", operationResult ? "" : "不");
} else {
printf("顺序栈未初始化或已经被销毁,无法进行判空操作!\n");
}
break;
case 5: // 返回顺序栈长度
if(isInitialized&&!isDestroyed) {
// 调用求顺序栈长度的函数,返回顺序栈长度
operationResult = StackLength(&s);
printf("顺序栈的长度为:%d。\n", operationResult);
} else {
printf("顺序栈未初始化或已经被销毁,无法进行求长度操作!\n");
}
break;
case 6: // 返回栈顶元素
if(isInitialized&&!isDestroyed) {
operationResult = GetTop(&s, &item);
if (operationResult) {
printf("顺序栈的栈顶元素为:%d。\n", item);
}
} else {
printf("顺序栈未初始化或已经被销毁,无法进行求栈顶操作!\n");
}
break;
case 7: // 插入新栈顶元素
if(isInitialized&&!isDestroyed) {
printf("请输入要入栈的元素:");
scanf("%d", &item);
operationResult = Push(&s, item);
if (operationResult) {
printf("元素%d成功入栈。\n", item);
}
} else {
printf("顺序栈未初始化或已经被销毁,无法进行入栈操作!\n");
}
break;
case 8: // 删除栈顶元素并返回其值
if(isInitialized&&!isDestroyed) {
operationResult = Pop(&s, &item);
if (operationResult) {
printf("删除的栈顶元素为:%d。\n", item);
}
} else {
printf("顺序栈未初始化或已经被销毁,无法进行删除操作!\n");
}
break;
case 9: // 输出栈内元素
if(isInitialized&&!isDestroyed) {
PrintStack(&s);
} else {
printf("顺序栈未初始化或已经被销毁,无法进行输出操作!\n");
}
break;
case 10: // 创建并输入顺序栈元素
CreateStack(&s);
isInitialized = true; // 初始化标志设置为true
isDestroyed = false; // 销毁标志设置为false
break;
case 11: // 十进制转二进制
if(isInitialized&&!isDestroyed) {
printf("请输入要转换的十进制数:");
scanf("%d", &num);
DecToBin(&s, num);
} else {
printf("顺序栈未初始化或已经被销毁,无法进行转换操作!\n");
}
break;
case 12: // 退出程序
quit = 1;
DestroyStack(&s); // 程序结束前销毁栈
printf("程序已结束。\n");
break;
default:
printf("操作码无效,请重新输入!\n");
}
}
return 0;
}
//From:TengMMVP