一 、目的:
加深对抽象数据类型 ADT 栈和队列的理解;
二 、环境:
operating system version:Win11
CPU instruction set: x64
Integrated Development Environment:Viusal Studio 2022
三 、内容:
编写程序实现ADT栈的定义,及常用操作(数组或指针实现
1) 生成栈
2) Push
3) Pop
编写程序实现ADT队列的定义,及常用操作:
1) 生成队列
2) Enqueues 入列
3) Isempty 判断是否队列为空 。
四 、步骤:
1.程序:
Part1:ADT栈的定义及常用操作
#include <stdio.h>
#define MAXSIZE 100
typedef struct node
{
int* base;
int* top;
int stacksize;
}Stack; //声明栈
int InitStack(Stack& S);//初始化栈
int Push(Stack& S, int e);//声明Push函数,实现压栈
void Pop(Stack& S);//声明Pop函数,实现出栈
int Get(Stack S);//声明Get函数,取出栈
void PrintStack(Stack& S);//声明PrintStack函数,输出所有元素
int main(int argc, char* argv[])
{
int num;
int Value;
int choice;
Stack S;
if (InitStack(S))//根据返回值判断初始栈是否完成
printf("Initialization completed\n");
printf("Enter the number of data to be pushed into the stack:");
scanf_s("%d", &num);
printf("Start Push\n");//开始压栈
for (int n = 0; n < num; n++)
{
printf("Please enter the data %d :", n + 1);
scanf_s("%d", &Value);
Push(S, Value);
}
PrintStack(S);
printf("Whether to perform Pop, 0 -> no others -> yes :");
scanf_s("%d", &choice);
if (choice)
Pop(S);
PrintStack(S);
return 0;
}
int InitStack(Stack& S) //初始化栈空间
{
S.base = new int[MAXSIZE];
if (!S.base) return 0;
S.top = S.base;
S.stacksize = MAXSIZE;
return 1;
}
int Push(Stack& S, int e) //压栈
{
if (S.top - S.base == S.stacksize) return 0;
S.top++;
*S.top = e;
return 1;
}
//出栈
void Pop(Stack& S) //删除栈顶元素并返回
{
printf("The top-of-stack value of %d has been removed\n", *S.top);
S.top--;
}
int Get(Stack S) //取栈
{
if (S.top != S.base)
return *(S.top - 1);
}
void PrintStack(Stack& S) //遍历栈
{
int i;
if (S.top == S.base) printf("Stack empty\n");
else
{
printf("The data in the stack is\n");
i = S.top - S.base;
for (int j = 0; j < i; j++)
{
printf("%d\n", *(S.top - j));
}
}
}
Part2:ADT队列的定义及常用操作
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct { //定义队列类型
char data[1001];
int Front;
int Rear;
int Size;
}Queue;
void InitQueue(Queue* Q) //初始化队列
{
Q->Front = 0;
Q->Rear = 0;
Q->Size = 0;
}
int IsEmpty(Queue* Q) //定义IsEmpty函数,判断队列是否为空
{
return Q->Size == 0;
}
void EnQueue(Queue* Q, int x) //定义EnQueue函数,进行入队列
{
Q->data[Q->Rear] = x;
Q->Rear++;
Q->Front = Q->Rear - 1;
Q->Size++;
}
int main()
{
Queue Q;
InitQueue(&Q);//初始化队列
EnQueue(&Q, 5);
EnQueue(&Q, 20);
EnQueue(&Q, 3);
EnQueue(&Q, 5);
printf("\nGenerated Queue\n");
int m = Q.Rear;
for (int i = 0; i < m; i++)
printf("%d ", Q.data[i]);
if (IsEmpty(&Q))//判断是否空队列
printf("\nEmpty queue\n");
else
printf("\nQueue non-empty\n");
int f;
for (int k = 4; k < 1001; k++)
{
printf("\nEnter incoming queue number:");
scanf_s("%d", &f);
EnQueue(&Q, f);
printf("Result:");
m = Q.Rear;
int i;
for (i = 0; i < m; i++)
printf("%d ", Q.data[i]);
if (IsEmpty(&Q))
printf("\nEmpty queue\n");
else
printf("\nQueue non-empty\n");
}
return 0;
}
2.程序结果:
栈:
(1)首先进行初始化栈测试,这里通过InitStack()函数返回值来判断是否初始化成功。若初始化成功,则输出Initialization completed。
(2)压栈
输入测试数据2023,可见按照FILO原则,栈内保存状态为3202.
(3)出栈
在这里将栈顶元素3出栈,然后输出栈内剩余元素,如下图所示。
综上,编写程序实现ADT栈的定义及常用操作(数组或指针实现
1) 生成栈2) Push 3) Pop
队列:
(1)生成队列,如下图所示
(2)入列操作如下图所示,这里以15和25为例:
(3)Isempty判断队列是否为空,即队列size是否为0。如下图所示,可见队列非空。
编写程序实现ADT队列的定义,及常用操作:
1) 生成队列2) Enqueues 入列3) Isempty 判断是否队列为空 。
2.分析和改进:
在实现ADT栈的中,完成了最终的生成栈、push和pop的操作,运行效果也符合预期,但是在实际的分析中我发现最初的设计逻辑中在push操作中遗漏了栈空间的限制,在我的小样本测试中程序运行完美,但是若压栈的输入数据远远地超过了栈本身的容量,就会不可避免地造成爆栈的情况,因此,在实际的设计中还要考虑栈的空间,我后来改用了采用push函数返回值的判断方法在一定程度上避免了爆栈的可能。如下:
int Push(Stack& S, int e) //压栈
{
if (S.top - S.base == S.stacksize) return 0;
S.top++;
*S.top = e;
return 1;
}
五 小结:
此次有关于ADT栈和队列的实现,虽然对栈和队列概念已经较为熟悉,但是在实际的编程中仍然有一些细节没有注意到,例如在压栈的时候不能一味地考虑压入以及指针的变化,还应该考虑到栈的空间是否足够,以免出现爆栈的现象。
加强了我对于栈和队列的理解,也从实践的角度很好的掌握了栈和队列之间的区别。栈和队列是两种常用的数据结构,栈和队列是操作受限的线性表,栈和队列的数据元素具有单一的前驱和后继的线性关系;栈和队列又是两种重要的抽象数据类型。栈是限定在表尾进行插入和删除操作的线性表允许插入和删除的一端为栈顶,另一端为栈底,出栈元素只能是栈顶元素,后进先出,相邻元素具有前驱与后继关系。队列是只允许在一端进行插入操作,在另一端进行删除操作的线性表。允许插入的一端为队尾,允许删除的一端为队头,先进先出,相邻元素具有前驱与后继关系。