用栈ADT应用:对称符号匹配判断
输入一行符号,以#结束,判断其中的对称符号是否匹配。对称符号包括:
{ } 、 [ ] 、 ( )、 < >
输出分为以下几种情况:
(1)对称符号都匹配,输出 “ right. “
(2) 如果处理到最后出现了失配,则输出两行:
第一行:Matching failure.
第二行:loss of right character $$....
其中$$... 是按嵌套顺序对应的右匹配符号。
(3)处理到某个符号时失配了,则输出两行或三行:
第一行: The N character '$' is wrong." ,
其中N是出错符号的序号,$是出错的符号;
第二行: loss of left character $.”
其中 $ 是当前符号的左匹配符号。
第三行:(如果有的话)loss of right character $$...”
其中$$... 是按嵌套顺序对应的右匹配符号。
测试用例
用例一:
输入:
as(*x<{(({<>}))}>)#
输出:
right.
用例二:
输入:
(a.b)>#
输出:
The 6 character ‘>’ is wrong.
loss of left character <.
因为隐藏用力比较多,博主也寻找了很多隐藏用例,因此这里给出两个博主自己摸索的用例。这也用例也都满足,ac的概率更高一点
自创用例一:
输入:
{<{>}>}#
输出:
The 4 character ‘>’ is wrong.
loss of left character <.
loss of right character }>}.
自创用例二:
输入:
{{{}#
输出:
Matching failure.
loss of right character }}.
其实我这里自己写的也比较乱,做了一下午脑袋嗡嗡的。有几个要注意的坑:
1.对“栈”的理解;
之前看过一个博主写的非常好,我的印象很深刻。他说,栈就像一个口袋,先放进去的在最底下,只能最后取出来。最后放进去的在最顶上,能最先取出来。
我的栈定义写了
变量:
存放栈元素的数组 ElemType *elements;
栈顶指示器top,并赋初值为-1(运行程序的时候因为没赋初值报错了)
栈的最大容量maxsize
方法
栈的溢出处理void overflowProcess();
进栈 void Push(ElemType x);
出栈 bool Pop (ElemType x);
判断栈是否为空 bool IsEmpty()const;
判断栈是否栈满 bool IsFull();
取栈顶内容 bool GetTop(ElemType &x);
得到栈的容量 int GetSize()const;
栈置空void MakeEmpty();
其中本题只用到了进栈,出栈、判断栈是否为空,栈制空(析构函数中)
2.本题难点
这个题我觉得最难的地方是考虑多种失配情况。
这个题的中心思路是:
将输入的字符串进行比对,压进栈中→分析多种情况得到输出
(可能是我的算法太差了,我输出这里真是一言难尽,搞了好久)
(1)压栈时,左侧符号-({<[-直接进栈,当检测到右侧符号时(下面称其为当前符号),开始与比较。
- 当栈为空栈时,说明从第一个字符就开始错了,输出第一行
第一行: The N character ‘$’ is wrong." ,
然后将这个字符保存下来(我再程序中定义了一个全局变量),到后面比对输出。此时,后面的字符就不需要再遍历了,直接break;
- 当栈不是空栈时,比较栈顶和当前字符:
栈顶和当前符号适配时,让栈顶的符号出栈(Pop);
栈顶和当前符号不适配时,说明从这个字符开始错了,输出第一行
第一行: The N character ‘$’ is wrong." ,
同样的,将这个字符保存下来,然后break出循环;
这里需要注意,栈为空的不适配和栈不为空的不适配是不一样的,关系到输出时三行还是两行。所以要分别标记。
栈为空时的不适配,说明多余了右侧符号,此时只需要两行(输出所缺失的左侧符号,就像测试用例二)
栈不为空时不适配,说明右侧符号没法和栈内已有的左侧符号适配,此时需要输出三行(既要输出所确实的左侧符号,又要输出当前存在栈内的的符号的右侧符号,就像自创用例一)
(2)比对输出
首先分为两种情况,栈为空和栈不为空;
- 栈为空
(1)如果不存在失配现象(我的做法是设一个全局flag=0,然后一旦出现失配现象都让flag=1),说明可以完全适配,可以输出right;
(2)如果存在失配现象
说明多余了右侧符号,此时只需要两行(输出所缺失的左侧符号,就像测试用例二) - 栈不为空
(1)若无失配现象,说明是处理到了最后,符号不够和前边的匹配了。
此时输出:
第一行:Matching failure.
第二行:loss of right character $$…
其中第二行的“$$”就是把还在栈里的左侧符号的适配右侧符号输出(例如自创用例二)
(2)若有失配现象
那么既要输出这个适配符号的左侧符号,又要把还在栈里的左侧符号的适配右侧符号输出(自创用例一)
#include <iostream>
#include <assert.h>
#include <string>
using namespace std;
int countit=0;
char cun;
int judge=0; //栈内错误
int right1=0; //外部错误
char you;
typedef char ElemType;
class SeqStack
{
//顺序栈类定义
public:
ElemType *elements; //数组存放栈元素
int top=-1; //栈顶指示器
int maxSize; //栈最大容量
void overflowProcess(); //栈的溢出处理
SeqStack() {}
SeqStack(int sz); //构造函数
~SeqStack()
{
delete []elements;
}
void Push(ElemType x); //进栈
bool Pop(ElemType x); //出栈
bool GetTop(ElemType &x); //取栈顶内容
bool IsEmpty()const
{
return top==-1;
}
bool IsFull()const
{
return top==maxSize-1;
}
int GetSize()const
{
return top+1;
}
void MakeEmpty()
{
top=-1;
}
//friend ostream&operator<<(ostream &os,SeqStack &S); //重载运算符<<
};
SeqStack::SeqStack(int sz) //构造函数
{
elements=new ElemType[sz]; //申请连续空间
assert(elements!=NULL); //头文件,#include <assert.h>,宏断言,如果括号内语句是假就结束程序
top=-1; //栈顶指示器指向栈底
maxSize=sz; //栈的最大空间
}
void SeqStack::overflowProcess()
{
//私有函数,当栈满则执行扩充栈存储空间处理
ElemType *newArray=new ElemType[2*maxSize]; //创建更大的存储数组
for(int i=0; i<=top; i++)
{
newArray[i]=elements[i];
}
maxSize+=maxSize; //栈空间扩大
delete []elements; //释放原来的连续空间
elements=newArray; //改变elements指针
}
void SeqStack::Push(ElemType x)
{
//若栈满,则溢出处理,将元素X插入该栈栈顶
if(IsFull()==true)
overflowProcess(); //栈满
top++;
elements[top]=x; //栈顶指针先+1.再元素进栈
}
bool SeqStack::Pop(ElemType x)
{
//若栈不空,函数退出栈顶元素并将栈顶元素赋值给X
//返回true,否则返回false
if(IsEmpty()==true)
return false;
x=elements[top--]; //先去元素,栈顶指针退1
return true; //退栈成功
}
int main()
{
string str;
cin>>str;
SeqStack s(1000);
int i=0;
while(str[i]!='#')
{
if(str[i]=='(')
{
s.Push('(');
}
if(str[i]=='[')
{
s.Push('[');
}
if(str[i]=='<')
{
s.Push('<');
}
if(str[i]=='{')
{
s.Push('{');
}
if(str[i]==')')
{
if(s.IsEmpty()!=true) //如果栈非空
{
if(s.elements[s.top]=='(') //如果栈顶适配,则让栈顶出栈
{
s.Pop('(');
}
else //如果栈顶不适配,那么就有错,记下来这个符号然后break;
{
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
cun=str[i];
countit++;
judge=1;
break;
}
}
else //如果栈是空的,那么就错了
{
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
you=str[i];
right1++;
judge=1;
break;
}
}
if(str[i]==']')
{
if(!s.IsEmpty()) //如果栈非空
{
if(s.elements[s.top]=='[') //如果栈顶适配
{
s.Pop('[');
}
else
{
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
cun=str[i];
countit++;
judge=1;
break;
}
}
else //如果栈是空的
{
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
you=str[i];
right1++;
judge=1;
break;
}
}
if(str[i]=='>')
{
if(!s.IsEmpty()) //如果栈非空
{
if(s.elements[s.top]=='<')
{
s.Pop('<');
}
else
{
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
cun=str[i];
countit++;
judge=1;
break;
}
}
else //如果栈是空的
{
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
you=str[i];
right1++;
judge=1;
break;
}
}
if(str[i]=='}')
{
if(!s.IsEmpty()) //如果栈非空
{
if(s.elements[s.top]=='{')
{
s.Pop('{');
}
else
{
//收栈内的错误
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
cun=str[i];
countit++;
judge=1;
break;
}
}
else //如果栈是空的
{
cout<<"The "<<i+1<<" character '"<<str[i]<<"' is wrong."<<endl;
you=str[i];
right1++;
judge=1;
break;
}
}
i++;
}
if(s.IsEmpty()==true) //空栈时
{
if(right1==0 && judge==0) //不存在失配现象,那么就是right
{
cout<<"right."<<endl;
}
else if(right1!=0) //其他情况都是不适配。
//输出缺失的左侧运算符
{
cout<<"loss of left character ";
if(you=='>')
{
cout<<"<";
}
if(you==')')
{
cout<<"(";
}
if(you=='}')
{
cout<<"{";
}
if(you==']')
{
cout<<"[";
}
cout<<"."<<endl;
}
}
else //没空栈时
{
if(countit==0 ) //看有没有匹配完
{
cout<<"Matching failure."<<endl;
}
else if(countit!=0)
{
cout<<"loss of left character ";
if(cun=='>')
{
cout<<"<";
}
if(cun==')')
{
cout<<"(";
}
if(cun=='}')
{
cout<<"{";
}
if(cun==']')
{
cout<<"[";
}
cout<<"."<<endl;
}
cout<<"loss of right character ";
while(s.IsEmpty()!=true)
{
if(s.elements[s.top]=='{')
{
cout<<"}";
s.Pop('{');
}
if(s.elements[s.top]=='(')
{
cout<<")";
s.Pop('(');
}
if(s.elements[s.top]=='[')
{
cout<<"]";
s.Pop('[');
}
if(s.elements[s.top]=='<')
{
cout<<">";
s.Pop('<');
}
}
cout<<"."<<endl;
}
return 0;
}
代码写的有点乱,思路也比较乱,如果发现错误欢迎批评指正