栈的理解与例题:
例题:
本题实现求表达式中括号是否匹配。只需判断表达式中括号(本题中只会出现三种括号,分别是小括号,中括号和大括号)是否匹配,表达式中可以有其他值也可没有。(本题是一道函数题,程序主体由裁判系统给出)。
函数接口定义:
int match (char *exp);
其中 "exp" 为需判断括号是否正确的表达式,返回值为1或0,如果为1,则表示括号匹配,0表示不匹配。
裁判测试程序样例:
#include <stdio.h>
#define N 20
int match (char *exp);
int main()
{
char s[N];
int flag;
scanf("%s",s);
flag=match(s);
if(flag)
printf("%s match",s);
else
printf("%s not match",s);
return 0;
}
/* 请在这里填写答案 */
输入样例1:
{[2*(3+2)-7]}/4
输出样例1:
{[2*(3+2)-7]}/4 match
输入样例2:
{[()]}
输出样例2:
{[()]} match
思想解析:
1. 栈的定义
对于括号匹配类似的题目,用堆栈可以很方便的解决。想要解决这道题目我们首先需要知道栈是什么。
堆栈(Stack)也成为栈,是限定仅在表的一端进行插入和删除操作的线性表。通常将进行插入和删除的一端(表尾)叫做栈顶(top),不允许插入和删除的另一端(表头)叫做栈底(bottom),不含任何元素的栈叫做空栈。
插入数据元素的操作叫做进栈,也称压栈、入栈。删除数据元素的操作叫做出栈,也称为退栈。由于堆栈元素的插入和删除只是在栈顶进行的,总是后进去的元素先出来,所以堆栈又称为 后进先出线性表 或 LIFO ( Last In First Out ) 表。堆栈在日常生活中也经常见到,比如将子弹装入弹夹式的手枪,弹夹的一端是封闭的,子弹的放入和取出都是从弹夹的一端进行的,它就是一个堆栈。
理解堆栈的定义时需要注意:它是一个线性表,也就是说,栈元素具有线性关系,即前趋后继关系。并且在使用栈时,注意区分两个易混淆的概念:栈顶(top)和栈底(bottom)。
2. 栈的基本运算
对于栈的基本运算,常见的有以下几种。
InitStack (&S) | 初始化栈:构建一个空栈 S |
ClearStack (&S) | 置空栈:将 S 置为空栈 |
StackLength (S) | 求栈的长度:返回栈 S 中的元素个数 |
StackEmpty (S) | 判断栈是否为空:若栈S为空则返回真;否则返回假 |
Push (&S, e) | 进栈:将插入元素e为新的栈顶元素 |
Pop (&S, &e) | 出栈:若栈不为空,则删除 S 的栈顶元素,用e返回其值 |
GetTop (S, &e) | 取栈顶元素:返回当前栈顶的元素,并将其赋值给e |
DispStack (S) | 显示元素:从栈底到栈顶依次显示栈中的每个元素 |
(详细的栈的顺序储存和实现会再出一期)
3. 具体问题具体分析
在这道题目中,其要求我们对于括号进行匹配判断,其中包含大、中、小 三种括号"( )"/"[ ]"/"{ }"。括号匹配的条件显然是:一个左半小括号 " ( " 对应一个右半小括号 " ) " ;一个左半中括号 " [ " 对应一个右半中括号 " ] " ;一个左半大括号 " { " 对应一个右半大括号 " } " ,例如: { [ ( ) ] } 。若出现了一个小括号对应一个中括号或者一个中括号对应一个大括号,都是不合法的。
很显然的是,合法的括号总是左半边先出现再出现右半边。如果我们在遍历一组字符串时,遇到左边半个括号(无论大中小)就入栈到栈S中,那么在入栈完所有的左边半个括号后,右边半个括号开始出现,这时候栈顶的元素一定是 某个大小(大中小)的左半边个括号,然后我们再继续遍历字符串,我们将总会得到一个某个大小的右半个括号,此时我们再将得到的右半边个括号于栈顶元素的括号比较,如果比较出来是配对的,那么将栈顶元素出栈,同时栈顶降低。若所有的括号全都互相匹配,那么在遍历完整个字符串后,栈将被出空,否则,栈中总有未被匹配走的括号残留。
对于 “ { [ ( ) ] } ” 这种情况,我们用图来体现一下。
Code:
#include<iostream>
#include<cstdio>
using namespace std;
#define N 20
/*函数接口*/
int match(char* exp)
{
typedef struct stack //定义结构体类型
{
int top;
int data[N];
}stack;
stack* s;
s = (stack*)malloc(sizeof(stack)); //申请空间(基于VS2019的细分要求)
s->top = -1; //简单的栈初始化(InitStack)
char e;
int i=0;
while(exp[i]!='\0') //判断是否遍历完了字符串
{
if (exp[i] == '(' || exp[i] == '[' || exp[i] == '{') //左括号的入栈操作
{
s->top++;
s->data[s->top] = exp[i];
}
if (exp[i] == ')') //右括号的判断操作:若匹配则出栈(没有方向);否则直接return 0;
{
e = s->data[s->top];
if (e == '(')
s->top--;
else return 0;
}
if (exp[i] == ']')
{
e = s->data[s->top];
if (e == '[')
s->top--;
else return 0;
}
if (exp[i] == '}')
{
e = s->data[s->top];
if (e == '{')
s->top--;
else return 0;
}
i++;
}
if (s->top == -1) //判断栈空满足条件
return 1;
else return 0;
}
/*主函数*/
int main()
{
char s[N];
int flag;
cin >> s; //or choose " scanf("%s",s); "
flag = match(s);
if (flag)
printf("%s match", s);
else
printf("%s not match", s);
return 0;
}
by 琛宝