南昌航空大学实验报告
课程名称: 数据结构A 实验名称: 实验三 栈的应用
班 级: XXX 学生姓名: XXX 学号: XXXXX
指导教师评定: XXX 签 名: XXX
一、实验目的
本实验是关于栈的应用,栈在各种高级语言编译系统中应用十分广泛,利用栈的“先进后出”的特点,分析C语言源程序代码中的的括号是否配对正确。
通过本实验的学习,可以理解栈的基本操作的实现。
二、实验内容
本实验要求设计一个算法,检验C源程序代码中的括号是否正确配对。对本算法中的栈的存储实现,我们采用的是顺序存储结构。要求能够在某个C源程序上文件上对所设计的算法进行验证。
三、程序分析
(1)int initStack(sqstack **s) 初始化一个栈
(2)int push(sqstack *s,char x) 入栈,栈满时返回FALSE
(3)char pop(sqstack *s) 出栈,栈空时返回NULL
(4)int Empty(sqstack *s) 判断栈是否为空,为空时返回TRUE
(5)int match(FILE *f) 对文件指针f对指的文件进行比较括号配对检验,从文件中每读入一个字符ch=fgetc(f),采用多路分支switch(ch)进行比较:
①若读入的是“[”、“{”或“(”,则压入栈中,
②若读入的是“]”,则:若栈非空,则出栈,判断出栈符号是否等于“[”,不相等,则返回FALSE。
③若读入的是“}”,则:若栈非空,则出栈,判断出栈符号是否等于“{”,不相等,则返回FALSE。
④若读入的是“)”,则:若栈非空,则出栈,判断出栈符号是否等于“(”,不相等,则返回FALSE。
⑤若是其它字符,则跳过。
文件处理到结束时,如果栈为空,则配对检验正确,返回TRUE。
(6)主程序main()中定义了一个文件指针,输入一个已经存在的C源程序文件。
四、程序源代码
过程见后续,不想看过程的直接拉到底即可。
简要过程:
首先,通过看ppt上的以及书上的代码,懂了,但没完全懂,在我看来十分的抽象,,类似于“空头支票”。
其次,通过在网上的一系列查找,发现了不少问题,然后通过自己编写。基本实现了设计要求,但同时爷发现了问题。就是对于ppt上以及书上的代码有了更深程度的理解,也是理解了,ppt上以及书上的代码使用了动态一维数组。
最后,对代码进行了修改,用动态一维数组(ppt上以及书上的代码)来代替的普通的静态一维数组,并且每接收一个字符就对其进行相应的操作(之前是先存储起来然后才进行操作)。
详细过程:
首先,对于栈的基本操作实现,ppt的22、23页。
出栈和入栈还好,尤其是初始化:
#define STACK_SIZE 100 /* 栈初始大小 */
#define STACKINCREMENT 10 /* 存储空间分配增量 */
typedef int ElemType ;
typedef struct sqstack
{ ElemType *bottom; /* 栈不存在时值为NULL */
ElemType *top; /* 栈顶指针 */
int stacksize ; /* 当前已分配空间,以元素为单位 */ }SqStack ;
这块起初在我看来就是定义了栈顶指针、栈底指针,以及一个栈的空间。感觉并没有什么用,好像是一张“空头支票”,看似美好,实则无用。
然后通过看书,发现也是如此,打着怀疑的态度写了起来,发现其实是有很多问题的。
其次,就去网上查了下,浏览了许多代码,然后根据“网络上大家的理解”以及“之前对于线性表的学习”建立了自己的思路。然后顺着自己的思路写下去,实现过程中也遇到很多问题。其中尤其是[[]以及[]]这两个例子,本应该是错误的,单结果总是显示正确,其中的[]]显示仅仅是只进行了一进一出两步操作:
通过多次修改,于是对其添加了一个计数变量,每次进行操作对其进行记录
if(ch[i]=='{'||ch[i]=='['||ch[i]=='('){push(S,ch[j]);j++;}
if(ch[i]=='}') if(Empty(S)==0)//栈非空
{temp=pop(S);if(temp!='{')sign++;j++;}
if(ch[i]==']') if(Empty(S)==0)
{temp=pop(S);if(temp!='[')sign++;j++;}
if(ch[i]==')') if(Empty(S)==0)
{temp=pop(S);if(temp!='(')sign++;j++;}
if(j!=(i+1))sign++;
因为对于最后一个],栈为空,则不会再出栈,所以只有一个出栈。
最后通过这句if(j!=(i+1))sign++;对其进行一个判断,判断是否处理完所有的输入量。解决了这个问题。
源代码:
#include<stdio.h>
#include<stdlib.h>
#define STACK_SIZE 100 /* 栈初始大小 */
#define ElemType char
typedef struct SqStack
{
int bottom; /* 栈不存在时值为NULL */
int top; /* 栈顶指针 */
// char *T;
char T[STACK_SIZE]; /* 当前已分配空间,以元素为单位 */
}SqStack;
void init_Stack(SqStack &S)
{
S.bottom=0;
S.top=0; /* 栈空时栈顶和栈底指针相同 */
}
void push(SqStack &S,ElemType e)
{
S.T[S.top]=e;
(S.top)++;/* 栈顶指针加1,e成为新的栈顶 */
}
ElemType pop(SqStack &S)/*弹出栈顶元素*/
{
ElemType e;
(S.top)--;
e=S.T[S.top];
return e;
}
int Empty(SqStack S)
{
if(S.top==S.bottom)return 1;//栈空
return 0;//栈非空
}
int main()
{
SqStack S;
char ch[STACK_SIZE],temp;
int sign=0;//正误标志
int j=0;//计数,即进行了多少次操作,是否和当前位一致,防止少操作
init_Stack(S);
printf("需判断的括号串:");
gets(ch);
for(int i=0;ch[i]!='\0';i++)
{
if(ch[i]=='{'||ch[i]=='['||ch[i]=='('){push(S,ch[j]);j++;}
if(ch[i]=='}')
if(Empty(S)==0)//栈非空
{
temp=pop(S);if(temp!='{')sign++;
j++;
}
if(ch[i]==']')
if(Empty(S)==0)
{
temp=pop(S);if(temp!='[')sign++;
j++;
}
if(ch[i]==')')
if(Empty(S)==0)
{
temp=pop(S);if(temp!='(')sign++;
j++;
}
if(j!=(i+1))sign++;//判断是否和当前位一致,若不一致,则报错
}
if(Empty(S)==0)sign++;//运行完检查栈内是否还有元素,若有,则报错
if(sign==0)printf("zfc 正确!\n");
else printf("zfc 错误!\n");
return 0;
}
通过这部分编写,发现了一些问题,其次便看到了网上(https://zhidao.baidu.com/question/193809143.html)的这篇回答。
c语言 一维数组如何增加长度
然后就发现ppt上以及书上的代码并非“空头”,而是使用了动态一维数组,一切都解释的通了。
#define STACK_SIZE 100 /* 栈初始大小 */
#define STACKINCREMENT 10 /* 存储空间分配增量 */
typedef int ElemType ;
typedef struct sqstack
{ ElemType *bottom; /* 栈不存在时值为NULL */
ElemType *top; /* 栈顶指针 */
int stacksize ; /* 当前已分配空间,以元素为单位 */ }SqStack ;
而其中的bottom应该是对应的p,也就是数组指针,也是栈底指针。
最后,使用动态一维数组(ppt上以及书上的代码)来代替的普通的静态一维数组。
typedef struct SqStack
{
ElemType *bottom; //栈底,也是储存空间的首地址(动态一维数组)
ElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配空间,以元素为单位 */
}SqStack;
可以看到与ppt上的方法(下方代码)基本一致。
#define STACK_SIZE 100 /* 栈初始大小 */
#define STACKINCREMENT 10 /* 存储空间分配增量 */
typedef int ElemType ;
typedef struct sqstack
{ ElemType *bottom; /* 栈不存在时值为NULL */
ElemType *top; /* 栈顶指针 */
int stacksize ; /* 当前已分配空间,以元素为单位 */ }SqStack ;
然后再通过对于课本P47的理解,其中最为重要的几句代码:
1.初始化函数(void init_Stack(SqStack &S))中的初始分配语句:
S.bottom=(ElemType *)malloc(STACK_SIZE*sizeof(ElemType));
2.以及入栈函数(void push(SqStack &S,ElemType e))中的重新分配语句(即扩建语句):
S.bottom=
(ElemType *)realloc(S.bottom,(STACKINCREMENT+S.stacksize)*sizeof(ElemType)); /* 追加存储空间 */
3.还有入栈出栈函数中的赋值读值语句:
入栈:
*S.top=e;
出栈:
e=*S.top;
另,上次主函数的输入是,先通过数组保存,再对其元素进行入栈出栈操作。这次打算每接收符号,就直接对其操作。其中用到了while((ch=getchar())!='\n')这句。
并且为了观察的方便,让主函数进入了循环中,在主函数添加了while(1)。
最终得到源代码:
#include<stdio.h>
#include<stdlib.h>
#define STACK_SIZE 100 /* 栈初始大小 */
#define STACKINCREMENT 10 /* 存储空间分配增量 */
#define ElemType char
typedef struct SqStack
{
ElemType *bottom; //栈底,也是储存空间的首地址(动态一维数组)
ElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配空间,以元素为单位 */
}SqStack;
void init_Stack(SqStack &S)
{
S.stacksize=STACK_SIZE;
S.bottom=(ElemType *)malloc(STACK_SIZE*sizeof(ElemType));
if (!S.bottom)printf("FALSE!");
S.top=S.bottom;
}
void push(SqStack &S,ElemType e)
{
if(S.top-S.bottom>=S.stacksize) //栈满
{
S.bottom=
(ElemType *)realloc(S.bottom,(STACKINCREMENT+S.stacksize)*sizeof(ElemType)); /* 追加存储空间 */
if(!S.bottom)printf("FALSE!");
S.top=S.bottom+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
*S.top=e;
(S.top)++;/* 栈顶指针加1,e成为新的栈顶 */
}
ElemType pop(SqStack &S)/*弹出栈顶元素*/
{
ElemType e;
if(S.top==S.bottom){printf("NULL!");return 0;}/* 栈空,返回失败标志 */
(S.top)--;
e=*S.top;
return e;
}
int Empty(SqStack S)
{
if(S.top==S.bottom)return 1;//栈空
return 0;//栈非空
}
int main()
{
while(1)
{
SqStack S;
char ch,temp;
int sign=0;//正误标志
int i=0;//输入的字符串的长度
int j=0;//计数,即进行了多少次操作,是否和当前位一致,防止少操作
init_Stack(S);
printf("需判断的括号串:");
while((ch=getchar())!='\n')
{
if(ch=='{'||ch=='['||ch=='('){push(S,ch);j++;}
if(ch=='}')
if(Empty(S)==0)//栈非空
{
temp=pop(S);if(temp!='{')sign++;
j++;
}
if(ch==']')
if(Empty(S)==0)
{
temp=pop(S);if(temp!='[')sign++;
j++;
}
if(ch==')')
if(Empty(S)==0)
{
temp=pop(S);if(temp!='(')sign++;
j++;
}
if(j!=(i+1))sign++;//判断是否和当前位一致,若不一致,则报错
i++;
}
if(Empty(S)==0)sign++;//运行完检查栈内是否还有元素,若有,则报错
if(sign==0)printf("所输入括号配对正确!\n\n");
else printf("所输入括号配对有误!\n\n");
}
return 0;
}
写到这里本应是结束了的,可是我忽略了一点要求中的:
⑤若是其它字符,则跳过。
不过也是一点小问题,更改主函数中的
if(j!=(i+1))sign++;//判断是否和当前位一致,若不一致,则报错
i++;\n");
为
if(ch=='{'||ch=='['||ch=='('||ch=='}'||ch==']'||ch==')')i++;
if(j!=i)sign++;//判断是否和当前位一致,若不一致,则报错
即可。
源代码:
#include<stdio.h>
#include<stdlib.h>
#define STACK_SIZE 100 /* 栈初始大小 */
#define STACKINCREMENT 10 /* 存储空间分配增量 */
#define ElemType char
typedef struct SqStack
{
ElemType *bottom; //栈底,也是储存空间的首地址(动态一维数组)
ElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配空间,以元素为单位 */
}SqStack;
void init_Stack(SqStack &S)
{
S.stacksize=STACK_SIZE;
S.bottom=(ElemType *)malloc(STACK_SIZE*sizeof(ElemType));
if (!S.bottom)printf("FALSE!");
S.top=S.bottom;
}
void push(SqStack &S,ElemType e)
{
if(S.top-S.bottom>=S.stacksize) //栈满
{
S.bottom=
(ElemType *)realloc(S.bottom,(STACKINCREMENT+S.stacksize)*sizeof(ElemType)); /* 追加存储空间 */
if(!S.bottom)printf("FALSE!");
S.top=S.bottom+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
*S.top=e;
(S.top)++;/* 栈顶指针加1,e成为新的栈顶 */
}
ElemType pop(SqStack &S)/*弹出栈顶元素*/
{
ElemType e;
if(S.top==S.bottom){printf("NULL!");return 0;}/* 栈空,返回失败标志 */
(S.top)--;
e=*S.top;
return e;
}
int Empty(SqStack S)
{
if(S.top==S.bottom)return 1;//栈空
return 0;//栈非空
}
int main()
{
while(1)
{
SqStack S;
char ch,temp;
int sign=0;//正误标志
int i=0;//输入的字符串的长度
int j=0;//计数,即进行了多少次操作,是否和当前位一致,防止少操作
init_Stack(S);
printf("需判断的括号串:");
while((ch=getchar())!='\n')
{
if(ch=='{'||ch=='['||ch=='('){push(S,ch);j++;}
if(ch=='}')
if(Empty(S)==0)//栈非空
{
temp=pop(S);if(temp!='{')sign++;
j++;
}
if(ch==']')
if(Empty(S)==0)
{
temp=pop(S);if(temp!='[')sign++;
j++;
}
if(ch==')')
if(Empty(S)==0)
{
temp=pop(S);if(temp!='(')sign++;
j++;
}
if(ch=='{'||ch=='['||ch=='('||ch=='}'||ch==']'||ch==')')i++;
if(j!=i)sign++;//判断是否和当前位一致,若不一致,则报错
}
if(Empty(S)==0)sign++;//运行完检查栈内是否还有元素,若有,则报错
if(sign==0)printf("所输入括号配对正确!\n\n");
else printf("所输入括号配对有误!\n\n");
}
return 0;
}
运行图: