括号匹配

括号匹配这个问题,说难好难,但是说简单好像也挺简单,主要就是看我们的思路是否清晰,条例是否清楚。

基本问题是:给定一串字符,可能包括括号、数字、字母、标点符号、空格,检查这一串字符中的( ) ,[ ],{ }是否匹配,匹配输出yes,反之输出no。

我们可以先确定最基本的逻辑,就是对输入的数一一判断,如果是左括号就存起来,等到有有括号的时候进行配对,配对成功继续输入,错了就可以退出了。

于是,数据结构自然而然就是用栈了,而我用的是顺序栈。

先说说我最开始的想法啦。

1. 由于首先要读入一串字符,而且包括空格,但是判断的时候只能一个一个判断,所以就先给个数组存这串字符,用下标表示单个字符。

2. 然后为了方便地控制循环,我用strlen取得了字符的长度。

3. 设置了一个result参数,用于表示括号是否匹配的状态,1表示匹配成功,0表示不匹配。并将其初始化为1,这样可以避免额外讨论字符串中没有括号的情况。(没有括号也算匹配成功)

4. 接下来就是匹配环节了。遍历我们之前的数组,遇到左括号入栈;遇到右括号,把这个右括号和出栈的值尝试匹配,成功就继续扫描,失败不用扫描了,直接输出no吧。但是由于我用result表示是否匹配,所以我选择吧result的值变为0,然后退出循环。

5. 遍历的循环结束后,判断是否匹配,即判断result为0还是为1。

看起来没啥问题,但接着考虑一下,由于我的result初值为1,即默认匹配,会不会存在一种情况使括号即使不匹配,但是由于没有改变result的值而导致错误呢?

那么来看看什么时候result会改变。仅当扫描到右括号才会进行匹配尝试,而仅当匹配失败才会使result为0。也就是说,不扫描到右括号,result是没机会匹配的。

于是我们会想,只有左括号呢?如果没有对应的右括号,即使不匹配,result仍然为1。

那么就必须额外加一个条件来排除上述情况。显然这种情况下,栈中一定有左括号,即栈一定非空。那么反过来说,如果括号匹配,栈就一定为空。于是想到最后判断匹配的条件是:result=1且栈为空。

关键代码如下:

 1 cin.getline(a, 100);
 2     length = strlen(a);        
 3     for (int i = 0; i <= length; i++) {        //
 4         if (a[i] == '(' || a[i] == '[' || a[i] == '{') {        //左括号入栈
 5             Push(stack, a[i]);
 6         }
 7         else if (a[i] == ')' || a[i] == ']' || a[i] == '}') {    //右括号,将其与出栈的字符尝试匹配
 8             temp = Pop(stack);                                
 9             if (!((a[i] == ')'&&temp =='(' )|| (a[i] == ']'&&temp == '[') || (a[i] == '}'&&temp == '{'))) {
10                 result = 0;            //如果不匹配就将result赋0
11                 break;
12             }
13         }
14     }
15     if (result == 1&&stack.base==stack.top) {        //匹配一定栈空,排除无右括号匹配,只有左括号
16         cout << "yes";
17     }
18     else {
19         cout << "no";
20     }

需要注意的是,栈顶指针所指的一直是顶元素的上一个。因此入栈的时候,现赋值再让栈顶指针+1;而出栈要反过来,先-1再赋值。一开始我先输出头指针的内容再让头指针减一,这就导致运行时错误。因为我忘了头指针为栈顶+1,因此其所指没有确切的值,导致非法访问。

原文地址:https://www.cnblogs.com/luoyang0515/p/10605065.html