python用栈实现括号匹配问题

问题描述:

给定一个字符串文字,里面可能含有"()","[]","{}"三种
括号,判断字符串中的括号是否都成对出现
***

思路分析:

如果括号正确匹配,肯定满足:
1、一对正确匹配的括号,一定先出现左括号,再出现右括号
2、三种括号不会出现交叉现象。如“{【】{}()()}”,而不会出现类似“(【)】”的情况。

如果以人类思维方式取匹配,过程如下:
遇到左括号先暂时不管,遇到右括号再看前面出现的左括号是否匹配。(而且由于括号不会交叉,遇到右括号后,查找的一定是距离最近的一个左括号)

最前面(最先)出现的左括号最后比较,最近出现的左括号先比较。因此,我们可以考虑利用栈“先进后出”的特性。

当遇到一个左括号,让它入栈;遇到一个右括号,则比较栈顶元素是否与之匹配。

首先创建一个Stack类

class Stack:
    def __init__(self):
        self.__list = []  # 初始化列表,存储栈中元素。因为不需要外界访问,所以私有化。

    def push(self, item):  # 弹出栈顶元素
        self.__list.append(item)

    def peek(self):
        return self.__list[len(self.__list) - 1]

    def pop(self):
        return self.__list.pop()   # 列表的pop方法,默认返回最后一个元素 

    def is_empty(self):   # 判断是否栈空
        return self.__list == []

遇到右括号,如何表示栈顶元素与括号“匹配”呢?*
一种思路是用字典键值对先存储对应的匹配关系

def is_matched_brackets(text):
    '''
        判断括号是否匹配
    :param text: 字符串类型
    :return:   True --> 全部匹配; False --> 不匹配
    '''
    dict_bracket = {')': '(', ']': '[', '}': '{'}   # 用字典的键值对存储匹配关系
    s = Stack()  # 创建一个栈对象,存储左括号
    for i in text:
        if i in dict_bracket.values():  # 左括号入栈 
            s.push(i)
        elif i in dict_bracket:  # 遇到右括号
            if s.is_empty():   # 栈空,说明剩余右括号未匹配
                print('missing left bracket')
                return False
            if s.peek() != dict_bracket[i]:  # 如果括号不匹配
                print('unmatched bracket')
                return False
            s.pop()  # 如果括号匹配则将左括号出栈
    if not s.is_empty():  # 循环结束。栈中还有元素,说明少右括号
        print('missing right bracket')
        return False
    return True

以上代码可以初步判断括号是否匹配。但如果想要更加精确的把未匹配的地方告诉用户,我们可以进一步判断未匹配括号的位置及括号的符号

我们只需在上述代码的基础上将左括号的索引位置以及括号一起存储到栈中即可
代码如下:

#  如果需要知道具体哪个位置的括号没有匹配
def is_matched_brackets2(text):
    dict_bracket = {')': '(', ']': '[', '}': '{'}
    s = Stack()  # 创建一个栈对象,存储左括号
    for i in range(len(text)):
        if text[i] in dict_bracket.values():  # 左括号入栈
            s.push((i, text[i]))  # 因为最后要记录剩余左括号未匹配的情况,所以索引也要存储
        elif text[i] in dict_bracket:  # 遇到右括号
            if s.is_empty() or s.peek()[1] != dict_bracket[text[i]]: # 栈空和缺少对应左括号可以归为一种情况
                print('unmatched right bracket {} at {}'.format(text[i], i))
                return False
            s.pop()  # 右括号匹配时,将左括号出栈
    if not s.is_empty():
        index, item = s.pop()
        print('unmatched left bracket {} at {}'.format(item, index))
        return False
    return True

在此次练习中,我有几个细节方面的问题,总结如下:
1、if i in dict_bracket.values():
第一次忘记写values后面的括号,报错为:
TypeError: argument of type ‘builtin_function_or_method’ is not iterable*

>>> dict_ = {1:'a',2:'b'}
>>> dict_.values
<built-in method values of dict object at 0x0000028ECFC9F500>
>>> type(dict_.values)
<class 'builtin_function_or_method'>

调用内置方法,需要加括号

2、

if text[i] in dict_bracket.values:  # 遇到左括号入栈
	s.push((i, text[i])) 

因为push函数的本质是调用列表的append()方法(见上文),所以传入的对象应该是一个整体。 s.push((i, text[i])) 内层括号将索引与括号符号一一个元组形式传递。

3、

if s.peek() != dict_bracket[i]:  # 如果括号不匹配
	print('unmatched bracket')

这个地方只能用peek()判断—查看栈顶元素,
不能用pop()— 弹出栈顶元素
否则括号不匹配,栈顶元素也被取出来

4、

 if s.is_empty() or s.peek()[1] != dict_bracket[text[i]]:
 # [1]表示对栈中元素(元组类型)索引,返回括号符号
 index, item = s.pop()
# 左边逗号分隔,python自动生成元组

5、第一次尝试用if判断时

    for i in text:
        if i is '(':  # 左括号入栈
            s.push(i)

报错为:
SyntaxWarning: “is” with a literal. Did you mean “==”?

is 是身份运算符,本质是通过id()函数比较的。我进行了以下尝试:

a = '(df'
for i in a:
    print(i is '(')

运行结果:True False False
也就是说,a[0] is ‘(’ 这个判断是没有问题的
这个问题是我所感到疑惑,尚未解决的。

上一篇:基于Selenium+Python的web自动化测试框架


下一篇:Python数据分析 | Pandas核心操作函数大全