栈的顺序表示和实现以及简单应用(C语言)
文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、顺序栈的基本概念
栈是限定仅在表尾进行插入或删除的线性表,又称为先进后出的线性表,本质是操作受限的线性表。
因此对于栈来说,表尾端有特殊的含义,称为栈顶,表头端称为栈顶。
顺序栈,即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置。
二、顺序栈要实现的基本功能及应用
实现工具:Dev
顺序栈要实现的基本功能:
- 构造一个空的顺序栈
- 批量元素入栈
- 对顺序栈进行销毁
- 对顺序栈进行重置
- 判断顺序栈是否为空
- 获取顺序栈的长度
- 获取栈顶元素
- 插入新的栈顶元素并返回其值
- 删除当前栈顶元素并返回其值
- 打印顺序栈
顺序栈要实现的简单应用:
- 括号匹配的检验
- 数制转换
二、代码实现:
1. 准备工作
在dev新建一个Source File文件即可
File>new>Source File
在实现程序时导入的头文件有
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<windows.h>
在这里我调用windows头文件是为了在后面的代码中修改控制台的名称,在实现线性表的顺序结构时真正用到的只有前三个头文件
在写代码之前先对一些表示结果状态的字符进行预定义
//函数结果状态代码
#define TRUE 1 //代码中出现TRUE相当于出现了1
#define FALSE 0 //出现FALSE相当于出现了0
#define OK 1 //出现OK相当于出现了1
#define ERROR 2 //出现ERROR相当于出现了2
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int SElemType;
在这里使用了typedef定义了Status和SElemType为int类型,也就是说之后的代码当中如果出现了Status和ElemType,它们与int作用相同
2. 顺序栈动态分配顺序存储结构
代码如下:
#define STACK_INIT_SIZE 100 //栈的储空间的初始分配量
#define STACKINCREMENT 10 //栈的存储空间的分配增量
typedef struct{
SElemType *top; //栈顶指针
SElemType *base; //栈底指针,在构造栈时和销毁栈时均为NULL
int stacksize; //当前已经分配的存储空间
}SqStack;
3.构造一个空的顺序栈
代码如下:
//构造一个空的顺序栈
Status InitStack(SqStack &S)
{
S.base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType)); //开辟一块连续的空间
if(!S.base) //如果存储空间分配失败
exit(OVERFLOW);
S.top = S.base; //当栈为空栈时栈底和栈顶指针位置相同
S.stacksize = STACK_INIT_SIZE; //更新栈的空间大小
return OK;
}
在构造空线性表时参数加&符号表示引用传递,确保形参和实参同时改变
S.base为顺序栈的栈底指针,S.top为顺序栈的栈顶指针,S.stacksize为顺序栈当前分配的空间大小
图示:
在这里解释一下为什么顺序表中有L.length来表示当前表中的元素个数而顺序栈中没有S.length来表示当前顺序栈中的元素个数?
原因: 因为在顺序栈中,有S.base栈底指针一直指向栈底,而S.top栈顶指针一直指向这栈顶元素的下一个位置,所以当前栈中的元素个数就是S.top-S.base,因此不需要再单独定义length来表示栈中的元素个数。
4. 批量元素入栈
代码如下:
//批量元素入栈
Status ValueStack(SqStack &S,int Num)
{
if(!S.base){ //如果栈不存在
printf("栈不存在,元素无法入栈\n");
return ERROR;
}
if(S.base != S.top){ //判断传来的顺序栈中是否为空栈
if(Num >= S.stacksize){ //如果要入栈的元素数量大于栈的空间大小
S.base = (SElemType *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SElemType));
S.stacksize = S.stacksize + STACKINCREMENT; //更新栈的空间大小
}
int temp[Num]; //定义一个辅助数组
for(int i = 1;i <= Num;i++){
printf("请输入第%d个元素的值:",i);
scanf("%d",&temp[i - 1]); //将之后输入的值暂时存储在临时数组中
}
for(int j = 1;j <= Num;j++){
*S.top = temp[j - 1];
S.top++;
}
printf("%d个元素入栈成功\n",Num);
}
else{
for(int i = 1;i <= Num;i++){
printf("请输入第%d个元素的值:",i);
scanf("%d",&S.base[i-1]);
*(S.top++);
}
printf("%d个元素入栈成功\n",Num);
}
//这条语句的目的是为了检测栈顶指针的位置是否在栈顶元素的下一个位置
//如果输出的值等于输入元素的个数,则说明此时栈顶指针和栈底指针的位置都在正确的位置
// printf("%d\n",S.top-S.base);
return OK;
}
在进行批量元素入栈前,先判断栈是否存在,判断栈是否存在只需要判断栈底指针S.base是否存在即可。因为栈是一种先进后出的线性表,所以先插入的元素就会直接放到栈底,如果栈底指针不存在则说明没有开辟连续的存储空间。
确定栈存在以后接着判断栈是否为空栈
①如果当前栈不是空栈:
在刚才讲到过S.top - S.base表示当前栈中的元素个数,S.stacksize表示栈的存储空间分配量,所以当S.top - S.base > S.stacksize时表示此时栈已满,需要再开辟一块连续的存储空间,这里用到了realloc函数,简单的介绍一下realloc函数:
realloc()函数:
作用:重新分配空间
参数:原空间基址,现需空间大小
返回值:1. 成功:新空间地址(本质上是一个数值) 2. 失败:NULL
如果此时栈没有满,此时S.top指向的是下一个元素的位置,再插入元素只需要将要批量插入元素的第一个值赋值给S.top所指向的存储空间,之后再执行S.top++即可
(在这里我定义了一个int类型的辅助数组temp[],先将输入的值暂时存储在临时数组中)
图示:
②如果当前栈是空栈:
如果当前栈为空栈,此时栈顶指针S.top与栈底指针S.base都指向开辟的第一块存储空间,再插入元素时不需要移动S.base指针,只需要移动S.top指针确保S.top指针一直指向栈顶元素的下一个位置即可
5. 对顺序栈进行销毁
代码如下:
//对顺序栈进行销毁
Status DistoryStack(SqStack &S)
{
if(!S.base){
printf("顺序栈不存在,无法销毁\n");
return ERROR;
}
free(S.base); //使用free函数,将之前动态分配的内存还给系统
S.stacksize = 0; //将栈的存储容量重置为0
S.top = NULL; //重置栈顶指针为NULL
S.base = NULL; //重置栈底指针为NULL
printf("顺序栈销毁成功\n");
return OK;
}
销毁顺序栈前我进行了栈是否存在的判断,如果顺序栈不存在就直接返回ERROR
S.base中存储的是初始化是动态分配内存首元素的地址,free函数的作用就是将之前动态分配的内存还给系统,但是在调用free函数之后,虽然归还了内存,但是S.base和S.top仍然指向原来的地址,而这个地址在归还内存之后程序便无权进行访问,所以此时S.base和S.top就成了两个野指针,重置S.base和S.top为NULL就是为了防止发生野指针访问的情况,接着将顺序栈的存储容量S.stacksize重置为0
6. 对顺序栈进行重置
代码如下:
//对顺序栈进行重置
Status ClearStack(SqStack &S)
{
if(!S.base){
printf("顺序栈不存在,不需要进行重置\n");
return ERROR;
}
S.top = S.base; //将栈底指针赋值给栈顶指针
printf("顺序栈重置成功\n");
return OK;
}
重置顺序栈时只需要将栈底指针的地址赋值给栈顶指针就可以了,因为栈顶指针和栈底指针都没有指向之前赋值过的元素,而且S.top=S.base时认为栈为空栈
其次在开辟一块连续的存储地址时,地址内也存在有原本的值,所以开辟出的新的存储空间并不是空的,在之后无论是销毁栈又或者是重新给栈进行赋值时都会将之前赋给存储空间的值覆盖掉
7. 判断顺序栈是否为空
代码如下:
//判断顺序栈是否为空
Status StackEmpty(SqStack S)
{
if(!S.base)
return ERROR;
if(S.top == S.base)
return TRUE;
else
return FALSE;
}
在判断顺序栈是否为空之前仍然要先判断顺序栈是否存在,其次判断顺序栈是否为空只需要判断栈顶指针和栈底指针的位置即可,因为在元素入栈与出栈时栈底指针S.base的位置是不会发生变化,所以当S.top(栈顶指针)=S.base(栈底指针)时说明当前顺序栈为空栈,否则顺序栈不为空栈。
当顺序栈不存在时返回ERROR,顺序栈为空栈时返回TRUE,顺序栈不为空栈时返回FALSE
8. 获取顺序栈的长度
代码如下:
//获取顺序栈的长度
Status StackLength(SqStack S)
{
if(!S.base){
printf("顺序栈不存在,没有长度\n");
return ERROR;
}
int K;
K = S.top - S.base;
printf("栈的长度为:%d\n",K);
return OK; //返回顺序栈的长度
}
在获取顺序栈的长度之前仍然要先进行顺序栈是否存在的判断,顺序栈的长度也称顺序栈的元素个数。
在上面提到过,在顺序栈中,栈顶指针指向栈顶元素的下一个位置,S.top - S.base即为顺序栈的元素个数,在这里我定义了一个int类型的数据K,也可以在顺序栈存在的前提下直接return S.top-S.base;
9. 获取栈顶元素
代码如下:
//获取栈顶元素
Status GetTop(SqStack S)
{
if(!S.base){
printf("顺序栈不存在,不存在栈顶元素\n");
return ERROR;
}else if(S.base == S.top){
printf("顺序栈为空栈,不存在栈顶元素\n");
return ERROR;
}
int e;
e = *(S.top - 1);
printf("栈顶元素为:%d\n",e);
return OK;
}
获取栈顶元素的操作在顺序栈存在且不为空栈的前提下进行,所以先加入了顺序栈是否存在并且存在是否为空栈的判断。
因为在顺序栈中栈顶指针S.top指向的是栈顶元素的下一个位置,所以在获取栈顶元素时只需要将*(S.top-1)地址存储的值赋给一个int类型的变量e即可。
在这里可能会对代码有疑问:将S.top向下移动之后不再将S.top指针移动回原本的位置?
解答:因为在获取栈顶元素的方法中,没有使用引用传递,所以此时改变了S.top的位置并不会影响到
原本的S.top的位置
10. 插入新的栈顶元素并返回其值
代码如下:
//插入新的栈顶元素并返回其值
Status Push(SqStack &S,SElemType e)
{
if(!S.base){
printf("顺序栈不存在,无法插入新的栈顶元素\n");
return ERROR;
}
else if(S.top - S.base >= S.stacksize) //此时顺序栈已满,追加存储空间
{
if(!S.base){ //如果存储空间分配失败
printf("存储空间分配失败\n");
exit(OVERFLOW);
}
S.base = (SElemType *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SElemType));
S.top = S.base + S.stacksize;
S.stacksize = S.stacksize + STACKINCREMENT; //更新栈的空间大小
}
*S.top = e;
S.top++;
return e; //返回新插入的栈顶元素的值
}
在插入新的栈顶元素时也应该进行顺序栈是否存在的判断,只有当顺序栈存在时才能进行新的栈顶元素的插入,在顺序栈存在时向栈顶插入元素时也要进行栈是否已满的判断。因为本身栈顶指针S.top就是指向栈顶元素的下一个位置,所以只需要将要插入的元素赋值给当前S.top指向的位置,再将S.top++即可
11. 删除栈顶元素并返回其值
代码如下:
//删除栈顶元素并返回其值
Status Pop(SqStack &S)
{
if(!S.base)
return -1;
else if(S.base == S.top)
return -2;
SElemType e;
e = *(S.top - 1);
S.top = S.top - 1;
return e; //返回被删除的栈顶元素的值
}
删除栈底元素也是建立在顺序栈存在并且不为空的前提下进行的
先定义一个SElemType(本质上是int)类型的变量e,再将当前S.top位置存储的值赋值给e,再将栈顶指针S.top向后移一位,使之前栈顶的上一个元素成为新的栈顶便完成了栈顶元素的删除,最后再将e返回
12. 打印顺序栈
代码如下:
//打印顺序栈
Status PrintStack(SqStack S)
{
if(!S.base){
printf("顺序栈不存在,无法打印\n");
return ERROR;
}
else if(S.base == S.top)
printf("顺序栈为空栈\n");
printf("当前顺序栈的元素为:");
for(int i = 0;i < (S.top-S.base);i++){
printf(" %d",S.base[i]);
}
printf("\n"); //换行
return OK;
}
打印顺序栈也是建立在顺序栈存在的基础上,顺序栈存在时利用for循环依次将栈中存储的元素打印出来,for循环中的判断条件为S.top - S.base,循环的次数为栈中所含有的元素个数
三、简单应用的实现:
1. 括号匹配
代码如下:
//括号匹配的检验
Status examine(char *List)
{
SqStack S;
S.base = S.top = NULL; //将空栈的栈顶和栈底指针赋值为NULL,因为此时并未对栈进行任何操作
InitStack(S); //构造一个空栈
int result;
int temp = 0;
int final = 0;
int length = strlen(List); //获取字符数组的长度
char Arrays[length]; //定义一个与传来的字符数组长度相等的字符数组作为辅助数组
if(length == 1)
{
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
return ERROR;
}
for(int i = 0;i < length;i++)
{
switch(List[i]) //利用switch语句来控制括号的入栈和出栈
{
case '(':
case '[':
case '{':
{
Arrays[i] = Push(S,List[i]);
temp = 1;
}break;
case ')':
case ']':
case '}':
{
Arrays[i] = Pop(S);
if(Arrays[i] == '(' && List[i] != ')') //如果遇到了右括号判断是否与之前入栈的左括号对应
final = -1; //如果左括号与右括号不匹配就将final的值修改为-1
else if(Arrays[i] == '[' && List[i] != ']')
final = -1;
else if(Arrays[i] == '{' && List[i] != '}')
final = -1;
}
}
}
if(StackEmpty(S) && temp != 1){
printf("您输入的序列中没有括号\n");
final = 2;
}
if(temp == 1 && !StackEmpty(S)){
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
return OK;
}
if(final == -1)
{
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
return OK;
}else if(final == 0 && temp == 1)
{
result = StackEmpty(S); //使用result接收判断是否为空栈的结果
if(result == TRUE)
printf("输入的序列括号匹配\n");
else if(result == FALSE)
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
// printf("%s\n",Arrays); //这条语句用于检测出栈的顺序
}
return OK;
}
括号匹配是栈的一个简单应用,在编写代码前要先想到几个问题:
- 当输入的一个序列中没有括号时
- 当只输入一个右括号时
- 左右两边的括号数目相同但是却不是配对的括号
思路:
在接收到用户从键盘输入的字符串之后调用strlen函数获取字符串的长度并赋值给int类型的数据length,利用for循环将接收到的字符串中的每一个元素进行遍历,for循环的判断条件就是刚才通过strlen函数获取到的字符串长度。
在for循环中嵌套一个switch语句,如果遇到"(","{","[“就调用入栈元素将其放入到栈中,遇到”)","}","]"后就从栈中取出栈顶元素,并判断取出的左括号是否与右括号匹配,如果不匹配则输出输入的序列长度并返回不匹配。
代码解释:
函数头传来的参数是之前用户从键盘输入的一个字符串类型的数据
- 先定义一个在之后空栈用来存储括号
- 再定义了int类型的变量final和temp作为标志变量并赋初值0
- 在进入for循环之前我定义了一个if语句,作用是当接收到的字符串长度为1时,直接返回不匹配
- 定义switch语句来判断元素元素是否需要入栈,如果遇到入栈操作就将标志变量temp赋值为1。在switch语句中如果遇到出栈操作就进行判断当前出栈的元素是否与当前辅助数组中存储的右括号匹配,如果不匹配就修改标志变量final的值为-1
- 在for循环结束后加一个if判断条件,如果在循环完成时都没有进行修改temp的值(也就是说没有进行任何入栈出栈操作),说明输入的序列中不存在括号,修改final的值为2
- 最后根据标志变量的值对所有情况进行判断并输出结果
2. 数制转换
代码如下:
//数制转换
void conversion(int Num,int time)
{
int e,Elem;
Elem = Num;
SqStack S;
S.base = S.top = NULL; //将空栈的栈顶和栈底指针赋值为NULL,因为此时并未对栈进行任何操作
InitStack(S); //构造一个空栈
while(Num)
{
Push(S,Num % time);
Num = Num / time;
}
printf("10进制整数%d对应的%d进制整数的值为:",Elem,time);
while(!StackEmpty(S)) //如果此时栈为空栈
{
e = Pop(S); //使用e接收删除的栈顶的值
printf("%d",e);
}
printf("\n"); //换行
}
思路:
十进制N和其它进制数的转换是计算机实现计算的基本问题,基于下列原理:
N=(n div d)*d+n mod d
( 其中:div为整除运算,mod为求余运算)
因此,如果将计算过程中所得到的其他进制的数的各位顺序进栈,则按出栈序列打印输出的即为与输入对应的其他进制数。
代码解释:
Num为要转换的十进制下的数,time为对应的其他进制的数
构造一个空栈用于存储所得的余数,利用while循环不断的将Num与time的余数入栈,再将Num的值变为Num/time,当Num为0退出while循环时再利用一次while来将之前入栈的元素依次出栈,所得即为十进制转换为对应进制下的数。
四. 运行结果演示:
1. 基本功能演示
①构造一个空栈
②批量元素入栈两次并判断长度以及打印(为了简便,每次入栈3个元素,分别为1,2,3)
③删除栈顶元素并返回其值
④插入新的栈顶元素520并打印顺序栈
⑤重置顺序栈并判断是否为空
⑥销毁顺序栈并判断是否为空
2. 简单应用演示
1.括号匹配
①输入一个不含括号的序列
②只输入一个括号
③输入左右括号数量相等但是并不匹配的序列
④输入一个符合要求的序列
2.数制转换
输入十进制下的数5转换为二进制下的数
总结
栈的本质是操作受限的线性表,,因此可称为限定性的数据结构。但从数据结构的角度看,它们是和线性表大不相同的一类重要的抽象数据类型。由于栈广泛的应用在各种软件系统中,因此在面向对象的程序设计中,是一种多型数据类型。
(附录)源码:
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<windows.h>
//函数结果状态代码
#define TRUE 1 //代码中出现TRUE相当于出现了1
#define FALSE 0 //出现FALSE相当于出现了0
#define OK 1 //出现OK相当于出现了1
#define ERROR 2 //出现ERROR相当于出现了2
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int SElemType;
#define STACK_INIT_SIZE 100 //栈的储空间的初始分配量
#define STACKINCREMENT 10 //栈的存储空间的分配增量
typedef struct{
SElemType *top; //栈顶指针
SElemType *base; //栈底指针,在构造栈时和销毁栈时均为NULL
int stacksize; //当前已经分配的存储空间
}SqStack;
//构造一个空的顺序栈
Status InitStack(SqStack &S)
{
S.base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType)); //开辟一块连续的空间
if(!S.base) //如果存储空间分配失败
exit(OVERFLOW);
S.top = S.base; //当栈为空栈时栈底和栈顶指针位置相同
S.stacksize = STACK_INIT_SIZE; //更新栈的空间大小
return OK;
}
//批量元素入栈
Status ValueStack(SqStack &S,int Num)
{
if(!S.base){ //如果栈不存在
printf("栈不存在,元素无法入栈\n");
return ERROR;
}
if(S.base != S.top){ //判断传来的顺序栈中是否为空栈
if(Num >= S.stacksize){ //如果要入栈的元素数量大于栈的空间大小
S.base = (SElemType *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SElemType));
S.stacksize = S.stacksize + STACKINCREMENT; //更新栈的空间大小
}
int temp[Num]; //定义一个辅助数组
for(int i = 1;i <= Num;i++){
printf("请输入第%d个元素的值:",i);
scanf("%d",&temp[i - 1]); //将之后输入的值暂时存储在临时数组中
}
for(int j = 1;j <= Num;j++){
*S.top = temp[j - 1];
S.top++;
}
printf("%d个元素入栈成功\n",Num);
}
else{
for(int i = 1;i <= Num;i++){
printf("请输入第%d个元素的值:",i);
scanf("%d",&S.base[i-1]);
*(S.top++);
}
printf("%d个元素入栈成功\n",Num);
}
//这条语句的目的是为了检测栈顶指针的位置是否在栈顶元素的下一个位置
//如果输出的值等于输入元素的个数,则说明此时栈顶指针和栈底指针的位置都在正确的位置
// printf("%d\n",S.top-S.base);
return OK;
}
//对顺序栈进行销毁
Status DistoryStack(SqStack &S)
{
if(!S.base){
printf("顺序栈不存在,无法销毁\n");
return ERROR;
}
free(S.base); //使用free函数,将之前动态分配的内存还给系统
S.stacksize = 0; //将栈的存储容量重置为0
S.top = NULL; //重置栈顶指针为NULL
S.base = NULL; //重置栈底指针为NULL
printf("顺序栈销毁成功\n");
return OK;
}
//对顺序栈进行重置
Status ClearStack(SqStack &S)
{
if(!S.base){
printf("顺序栈不存在,不需要进行重置\n");
return ERROR;
}
S.top = S.base; //将栈底指针赋值给栈顶指针
/*
重置顺序栈时只需要将栈底指针的地址赋值给栈顶指针就可以了
因为栈顶指针和栈底指针都没有指向之前赋值过的元素,而且S.top=S.base时认为栈为空栈
其次在开辟一块连续的存储地址时,地址内也会有原本的值,开辟出的新空间并不是空的
在之后无论是销毁栈又或者是重新给栈进行赋值时都会将之前赋的值覆盖掉
*/
printf("顺序栈重置成功\n");
return OK;
}
//判断顺序栈是否为空
Status StackEmpty(SqStack S)
{
if(!S.base)
return ERROR;
if(S.top == S.base)
return TRUE;
else
return FALSE;
}
//获取顺序栈的长度
Status StackLength(SqStack S)
{
if(!S.base){
printf("顺序栈不存在,没有长度\n");
return ERROR;
}
int K;
K = S.top - S.base;
/*
为什么顺序表中有length而顺序栈中却没有length
因为在顺序栈中,栈的长度就是S.top-S.base
*/
printf("栈的长度为:%d\n",K);
return OK; //返回顺序栈的长度
}
//获取栈顶元素
Status GetTop(SqStack S)
{
if(!S.base){
printf("顺序栈不存在,不存在栈顶元素\n");
return ERROR;
}else if(S.base == S.top){
printf("顺序栈为空栈,不存在栈顶元素\n");
return ERROR;
}
int e;
e = *(S.top - 1);
printf("栈顶元素为:%d\n",e);
return OK;
}
//插入新的栈顶元素并返回其值
Status Push(SqStack &S,SElemType e)
{
if(!S.base){
printf("顺序栈不存在,无法插入新的栈顶元素\n");
return ERROR;
}
else if(S.top - S.base >= S.stacksize) //此时顺序栈已满,追加存储空间
{
if(!S.base){ //如果存储空间分配失败
printf("存储空间分配失败\n");
exit(OVERFLOW);
}
S.base = (SElemType *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SElemType));
S.top = S.base + S.stacksize;
S.stacksize = S.stacksize + STACKINCREMENT; //更新栈的空间大小
}
*S.top = e;
S.top++;
return e; //返回新插入的栈顶元素的值
}
//打印顺序栈
Status PrintStack(SqStack S)
{
if(!S.base){
printf("顺序栈不存在,无法打印\n");
return ERROR;
}
else if(S.base == S.top)
printf("顺序栈为空栈\n");
printf("当前顺序栈的元素为:");
for(int i = 0;i < (S.top-S.base);i++){
printf(" %d",S.base[i]);
}
printf("\n"); //换行
return OK;
}
//删除栈顶元素并返回其值
Status Pop(SqStack &S)
{
if(!S.base)
return -1;
else if(S.base == S.top)
return -2;
SElemType e;
e = *(S.top - 1);
S.top = S.top - 1;
return e; //返回被删除的栈顶元素的值
}
/*
遇到的问题会有以下几点
1. 当输入的一个序列中没有括号时
2. 当只输入一个右括号时
3. 左右两边的括号数目相同但是却不是配对的括号
*/
//括号匹配的检验
Status examine(char *List)
{
SqStack S;
S.base = S.top = NULL; //将空栈的栈顶和栈底指针赋值为NULL,因为此时并未对栈进行任何操作
InitStack(S); //构造一个空栈
int result;
int temp = 0;
int final = 0;
int length = strlen(List); //获取字符数组的长度
char Arrays[length]; //定义一个与传来的字符数组长度相等的字符数组作为辅助数组
if(length == 1)
{
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
return ERROR;
}
for(int i = 0;i < length;i++)
{
switch(List[i]) //利用switch语句来控制括号的入栈和出栈
{
case '(':
case '[':
case '{':
{
Arrays[i] = Push(S,List[i]);
temp = 1;
}break;
case ')':
case ']':
case '}':
{
Arrays[i] = Pop(S);
if(Arrays[i] == '(' && List[i] != ')') //如果遇到了右括号判断是否与之前入栈的左括号对应
final = -1; //如果左括号与右括号不匹配就将final的值修改为-1
else if(Arrays[i] == '[' && List[i] != ']')
final = -1;
else if(Arrays[i] == '{' && List[i] != '}')
final = -1;
}
}
}
if(StackEmpty(S) && temp != 1){
printf("您输入的序列中没有括号\n");
final = 2;
}
if(temp == 1 && !StackEmpty(S)){
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
return OK;
}
if(final == -1)
{
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
return OK;
}else if(final == 0 && temp == 1)
{
result = StackEmpty(S); //使用result接收判断是否为空栈的结果
if(result == TRUE)
printf("输入的序列括号匹配\n");
else if(result == FALSE)
printf("输入的序列括号不匹配\n");
printf("输入的序列长度为:%d\n",length);
// printf("%s\n",Arrays); //这条语句用于检测出栈的顺序
}
return OK;
}
//数制转换
void conversion(int Num,int time)
{
int e,Elem;
Elem = Num;
SqStack S;
S.base = S.top = NULL; //将空栈的栈顶和栈底指针赋值为NULL,因为此时并未对栈进行任何操作
InitStack(S); //构造一个空栈
while(Num)
{
Push(S,Num % time);
Num = Num / time;
}
printf("10进制整数%d对应的%d进制整数的值为:",Elem,time);
while(!StackEmpty(S)) //如果此时栈为空栈
{
e = Pop(S); //使用e接收删除的栈顶的值
printf("%d",e);
}
printf("\n"); //换行
}
int main()
{
SetConsoleTitle("Dream_飞翔"); //控制windows终端控制台的名称
SqStack S;
S.base = S.top = NULL; //将栈顶和栈底指针赋值为NULL,因为此时并未对栈进行任何操作
int choose,index,Num,e,time,final;
while(1){
printf("*****************************************\n");
printf("* *\n");
printf("* 顺序栈的顺序表示和实现: *\n");
printf("* *\n");
printf("* 1. 构造一个空的顺序栈 *\n");
printf("* 2. 批量元素入栈 *\n");
printf("* 3. 对顺序栈进行销毁 *\n");
printf("* 4. 对顺序栈进行重置 *\n");
printf("* 5. 判断顺序栈是否为空 *\n");
printf("* 6. 获取顺序栈的长度 *\n");
printf("* 7. 获取栈顶元素 *\n");
printf("* 8. 插入新的栈顶元素并返回其值 *\n");
printf("* 9. 删除当前栈顶元素并返回其值 *\n");
printf("* 10. 打印顺序栈 *\n");
printf("* *\n");
printf("*****************************************\n");
printf("* *\n");
printf("* 栈的简单应用: *\n");
printf("* *\n");
printf("* 11. 括号匹配的检验 *\n");
printf("* 12. 数制转换 *\n");
printf("* *\n");
printf("*****************************************\n");
printf("* 13. 退出 *\n");
printf("*****************************************\n");
printf("请做出您的选择:");
scanf("%d",&choose);
switch(choose){
case 1:{
final = InitStack(S);
if(final == OK)
printf("空栈构造成功\n");
}
break;
case 2:
{
printf("请压入顺序栈的元素个数:");
scanf("%d",&Num);
ValueStack(S,Num);
}
break;
case 3:DistoryStack(S);break;
case 4:ClearStack(S);break;
case 5:{
final = StackEmpty(S);
if(final == ERROR){
printf("顺序栈不存在,无法判断是否为空\n");
break;
}
else if(final == TRUE)
printf("顺序栈是空栈\n");
else
printf("顺序栈不是空栈\n");
}
break;
case 6:StackLength(S);break;
case 7:GetTop(S);break;
case 8:{
printf("请输入要压入的元素:");
scanf("%d",&e);
final = Push(S,e);
if(final == e)
printf("新的栈顶元素插入成功\n");
}
break;
case 9:{
final = Pop(S);
if(final == -1){
printf("顺序栈不存在,无法删除栈顶元素\n");
break;
}else if(final == -2){
printf("顺序栈为空栈,无法删除栈顶元素\n");
break;
}
printf("栈顶元素删除成功\n");
printf("删除的栈顶元素为:%d\n",final);
}
break;
case 10:PrintStack(S);break;
case 11:
{
char List[30];
printf("请输入一个带有括号的序列:");
scanf("%s",List);
examine(List);
}
break;
case 12:{
printf("请输入一个非负的十进制整数:");
scanf("%d",&Num);
printf("请输入想要将其转换成多少进制下的数:");
scanf("%d",&time);
if(time <= 0)
{
printf("请输入一个有效值\n");
break;
}
conversion(Num,time);
}
break;
case 13:exit(0);
}
}
return 0;
}