这只是其中一个例题,看完我对这道题的分析之后,关于括号匹配的问题你肯定能够掌握个差不多。转载请注明本文链接!
目录
一、问题描述
Description
给你一串字符,不超过50个字符,可能包括括号、数字、字母、标点符号、空格,你的任务是检查这一串字符中的( ) ,[ ],{ }是否匹配。
Input
输入数据有多组,处理到文件结束。
Output
如果匹配就输出“yes”,不匹配输出“no”
Sample
Input (输入)
sin(20+10) {[}]
Output(输出)
yes no
二、问题分析
这是一道让我做了三天才做出来的题,只能说我太**,把简单的问题想的过于复杂了。那我们来分析一下括号匹配问题我们需要做什么,我们需要注意什么。
(1)、首先看到括号匹配问题,我们需要一个栈,这个栈是用来存储算术表达式中的左括号'(','{','['的。
(2)、在存储左括号时,我们需要判断一下栈是否已满,只要栈不满我们就可以把它直接压入到栈中。
(3)、当我们遇到右括号时,我们需要看一下当前栈中是否有元素,如果栈是空的,那么我们就不用判断下去了,直接结束程序,括号是不匹配的;如果栈中有元素,那我们我们就拿出来栈顶元素,与当前我们遇到的右括号进行匹配,如果他们是一对,那么我们就把当前栈中的左括号出栈,继续扫描算术表达式,循环执行第(2)个步骤和第(3)个步骤;如果不是一对,那么我们也不用继续下去了,直接结束程序,括号是不匹配的。
(4)、我们要知道括号是成对出现的,有左括号无右括号,有右括号无左括号,这都是不行的。需要注意的是:当我们判断括号是否匹配时,不能把栈顶的括号和当前的右括号是否相等作为判断条件。因为左括号和右括号肯定是不相等的。我们只能判断一下当前右括号是哪一种括号,然后我们手动的定义出它对应的左括号,用这个我们定义的左括号和栈顶括号进行是否相等的判断。
(5)、对于这道题来说,当我们遇到'\0'时才停止扫描,之所以是‘\0',是因为数组存储完毕后,系统会自动的在末尾加上'\0'用来标记数组存储到这里就结束了。否则一直扫描算数表达式中的括号。
(6)、扫描完算术表达式之后,我们要看一下当前栈中是否还有元素,如果没有元素了,说明括号匹配,如果栈中还有元素,说明不匹配。因为我们遇到匹配的括号就执行出栈操作,全部匹配的话,到最后栈中的元素应该是都栈了的。
三、代码实现
(一)、定义结构体
根据我们对栈的了解,我们要先定义一个结构体,这个结构体中有一个数组用于存储元素,还有一个栈顶标记位top。因为栈是后进先出的。我们只需要一个栈顶标记位就可以对这个栈进行进栈出栈判空等的操作。如果对栈的只是不够熟悉,请先看完有关栈的知识再接着往下看。
#include <stdio.h>
#include <stdlib.h>
#define Maxsize 100 //数组大小
typedef struct ST
{
char data[Maxsize]; //存储栈中的元素
int top; //栈顶标记位
}Stack; //用Stack来表示这个结构体
(二)、初始化栈
因为数组的下标是从0开始的,刚开始我们并没有存元素,那我们让top==-1即可。当存入元素的时候,让top+1,然后在它标记的位置存储元素即可。
void Init(Stack *L)
{
L->top=-1;
}
(三)、进栈函数
void Push(Stack *L,char x)
{
if(L->top>=Maxsize) //当我们栈满的时候就不能存储元素了
{
return;
}
L->top++; //让top先加一
L->data[L->top]=x; //在top标记的位置存储当前的元素x
}
(四)、判断栈是否为空
int Empty(Stack L)
{
if(L.top==-1)
{
return 1;//为空返回1
}
return 0; //不为空返回0
}
(五)、出栈函数
出栈的时候只需判断栈是否为空,如果不为空,那就让栈顶标记位top-1即可。
void Pop(Stack *L)
{
if(L->top==-1)
{
return;
}
L->top--;
}
(六)、获取栈顶元素
当我们遇到右括号的时候,我们就需要获取栈顶的元素了,来判断栈顶元素是否和当前右括号匹配。
char Get(Stack L)
{
return L.data[L.top];
}
(七)、主函数
我们上面定义的函数都很简单,主要是看我们在主函数中如何去调用上面这些函数,在什么情况下我们才能用到上面的函数。
int main()
{
Stack L; //定义一个栈
char s[100]; //定义一个字符数组用来存储我们输入的算术表达式
while(gets(s)) //用来获得我们输入的各个字符,包括空格
{
Init(&L); //我们先初始化栈L
int flag=1; //这个变量用来标记括号是否匹配成功
for(int i=0;s[i]!='\0';i++) //循环遍历我们输入的算术表达式中的括号
{
if(s[i]=='('||s[i]=='['||s[i]=='{') //如果是左括号我们就看能不能让它入栈
{
if(L.top<Maxsize) //栈没满我们就让左括号进栈,调用Push函数
{
char x=s[i];
//进栈
Push(&L,x);
}
}
else if(s[i]==')') //如果栈是这个右括号,就判断栈是否为空
{
if(Empty(L)) //栈为空,我们就标记flag=0,结束循环,括号不匹配
{
flag=0;
break;
}
else //栈不空,我们就获取栈顶元素,调用Get函数
{
if(Get(L)=='(') //括号匹配了,调用Pop函数,将左括号出栈
{
Pop(&L);
}
else //括号不匹配,那我们标记flag=0,结束循环,括号不匹配
{
flag=0;
break;
}
}
}
else if(s[i]=='}') //接下来的两个else if和上面的思想一致。
{
if(Empty(L))
{
flag=0;
break;
}
else //问题就出在这一句上
{
if(Get(L)=='{')
{
Pop(&L);
}
else
{
flag=0;
break;
}
}
}
else if(s[i]==']')
{
if(Empty(L))
{
flag=0;
break;
}
else
{
if(Get(L)=='[')
{
Pop(&L);
}
else
{
flag=0;
break;
}
}
}
}
if(!Empty(L)) //遍历完算术表达式之后,判断栈是否为空,如果不为空,标记flag=0;
{
flag=0;
}
if(flag==1&&Empty(L)) //只有flag=1并且栈是空的,我们才能说我们输入的括号是完全匹配的
{
printf("yes\n");
}
else
{
printf("no\n");
}
}
return 0;
}
(八)、运行结果
四、完整代码
#include <stdio.h>
#include <stdlib.h>
#define Maxsize 100
typedef struct ST
{
char data[Maxsize];
int top;
}Stack;
void Init(Stack *L)
{
L->top=-1;
}
void Push(Stack *L,char x)
{
if(L->top>=Maxsize)
{
return;
}
L->top++;
L->data[L->top]=x;
}
int Empty(Stack L)
{
if(L.top==-1)
{
return 1;//为空返回1
}
return 0; //不为空返回0
}
void Print(Stack L)
{
for(int i=L.top;i>-1;i--)
{
printf("%c ",L.data[i]);
}
}
void Pop(Stack *L)
{
if(L->top==-1)
{
return;
}
L->top--;
}
char Get(Stack L)
{
return L.data[L.top];
}
int main()
{
Stack L;
char s[100];
while(gets(s))
{
Init(&L);
int flag=1;
//printf("%s",s);
for(int i=0;s[i]!='\0';i++)
{
if(s[i]=='('||s[i]=='['||s[i]=='{')
{
if(L.top<Maxsize)
{
char x=s[i];
Push(&L,x);
}
}
else if(s[i]==')')
{
if(Empty(L))
{
flag=0;
break;
}
else
{
if(Get(L)=='(')
{
Pop(&L);
}
else
{
flag=0;
break;
}
}
}
else if(s[i]=='}')
{
if(Empty(L))
{
flag=0;
break;
}
else
{
if(Get(L)=='{')
{
Pop(&L);
}
else
{
flag=0;
break;
}
}
}
else if(s[i]==']')
{
if(Empty(L))
{
flag=0;
break;
}
else
{
if(Get(L)=='[')
{
Pop(&L);
}
else
{
flag=0;
break;
}
}
}
}
if(!Empty(L))
{
flag=0;
}
if(flag==1&&Empty(L))
{
printf("yes\n");
}
else
{
printf("no\n");
}
}
return 0;
}
总结:括号匹配问题比较经典,它完美的考察了我们对栈的理解,熟悉栈的操作是基本的,只有把它结合到具体的问题上加以运用才是真的掌握。理论联系实际,实践是检验真理的唯一标准。继续加油。