栈的应用——括号配对

南昌航空大学实验报告

课程名称:   数据结构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;
}

运行图:

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值