基本原理
要编写一个这样的程序,我们首先要知道,什么是栈(stack),其实简单讲,栈就是一种后进先出(LIFO)的数据结构。
而在括号匹配中,我们可以看一个这样的例子:
假设我有“( ( ) ]”这样一组括号,其实可以很容易发现,右小括号少了一个,或者说,右中括号多了一个,可见,通过记录不同类型括号的左右两边数,好像就能实现括号匹配检测?
那么假设我有“( [ ) ]” 这样的一组括号,虽然不同类型的左右括号数相等,但整体括号却不能实现匹配。
为什么这样说?我们可以注意下自己写过的一些算式,是不是类似这样:
{1+3*[6-4*(3+1)]+1}
如果说只要个数匹配就行,那我可不可以这样写?
{1+3*(6-4*[3+1}+1])
很显然这是不行的,无论是程序代码还是数学算式,括号都不能这样匹配,但是通过观察,我们可以发现一个规律:
1.第一个式子左括号中,最后出现的“(”,与右括号中,最先出现的“)”匹配,中括号同理。
2.第二个式子左括号中,最后出现的“【”,与右括号中,最先出现的“}”,并不匹配。
我们不难得出一个结论:最后出现的左括号,往往越着急与最先出现的右括号匹配。
编写代码
要想判断所有的括号是否匹配,我们要先判断任意两个括号是否匹配。
int MatchChar(char a, char b)
{
if ((a == '(' && b == ')') || (a == '[' && b == ']') || (a == '{' && b == '}'))
{
return 1;
}
else
{
return 0;
}
}
在这个函数中,我们任意输入两个括号,然后返回这两个括号的匹配结果,其中a为任意类型的左括号,b为同类型的右括号。
我们知道,我们需要让右括号去匹配左括号,所以要想办法把左括号存起来,即:压入栈,等待右括号与之匹配,这样,我们就能保证最后进入的左括号,始终最先去匹配。
可能匹配失败情况有以下几种:
1.左右括号不匹配(MatchChar返回0)
2.缺少左括号(右侧括号匹配时,栈空)
3.左括号剩余(右括号匹配完成,还有左括号剩余)
编写代码如下:
stack<char>s;
int MatchExp(char exp[])
{
for (int i = 0; exp[i] != '\0'; i++)
{
if (exp[i] == '(' || exp[i] == '[' || exp[i] == '{')
{
s.push(exp[i]); //如果是左括号,就入栈
}
else //如果是右括号
{
if (s.empty())return 0; //栈空,没有左匹配右,失败
else
{
if (!MatchChar(s.top(), exp[i]))return 0; //左右括号不匹配
else s.pop(); //匹配成功,栈顶元素出栈
}
}
}
if (!s.empty())return 0; //匹配完时还要左括号剩余,失败
return 1;
}
最后,我们来看全部代码:
#include<iostream>
#include<stack>
using namespace std;
stack<char>s;
int MatchChar(char a, char b)
{
if ((a == '(' && b == ')') || (a == '[' && b == ']') || (a == '{' && b == '}'))
{
return 1;
}
else
{
return 0;
}
}
int MatchExp(char exp[])
{
for (int i = 0; exp[i] != '\0'; i++)
{
if (exp[i] == '(' || exp[i] == '[' || exp[i] == '{')
{
s.push(exp[i]);
}
else
{
if (s.empty())return 0;
else
{
if (!MatchChar(s.top(), exp[i]))return 0;
else s.pop();
}
}
}
if (!s.empty())return 0;
return 1;
}
void Result(int result)
{
if (result)cout << "匹配成功!";
else cout << "匹配失败!";
}
int main()
{
char exp[100] = {};
scanf("%s", exp);
Result(MatchExp(exp));
return 0;
}