棧應用之括號匹配問題

問題描述

括號匹配問題,即給定一段文本text,括號是否有正確匹配的問題。括號由一個開括號如"(“和一個閉括號”)“組成,相互對應。這裏只考慮三種括號,即”()","[]","{}"。此外括號括起的片段,也可能會嵌套。

解決思路

這樣就不難總結出檢查括號配對的原則:從左到右遍歷text時,遇到的閉括號應該與最近遇到的且尚未匹配的開括號配對。
由於括號的出現可能嵌套,需要逐對匹配,即當前閉括號應該與前面最近的尚未配對的開括號匹配,下一個閉括號則與前面次近的括號匹配。也就是說,需要存儲的開括號的使用原則是後存入着先使用,即LIFO。進而如果一個開括號已經配對,就應刪除這個括號,爲後面匹配作準備,顯然使用棧保存遇到的開括號,配對後再相應地pop掉最近的開括號就可以正確支持這樣的匹配任務。
比如對於text="(dsaf[sd]d}",我們順序遍歷,將兩個開括號"(“和”[“順序壓入棧中,然後遇到第一個閉括號”]“與此時的棧頂”[“匹配,匹配成功就將該棧頂彈出並繼續,此時棧頂變成了第一個壓入棧中的”(",然後繼續遍歷,遇到閉括號"}“與此時的棧頂”(“不匹配,說明整個text括號匹配不成功。
當然還熬考慮這種情況text=”(dsaf[sd]d",按照上面的思路是不能檢測到"("丟失匹配的情況的,我們可以在遍歷text結束時再查看棧中是否還有剩餘的元素,如果有,說明是丟失匹配的開括號。
於是算法思路如下:

  • 順序遍歷給定text的一個個字符
  • 對於除了括號之外的無關字符直接跳過
  • 遇到開括號就壓入棧
  • 遇到比閉括號就彈出當時的棧頂元素與之匹配
  • 如果匹配成功則繼續,如果不匹配則以失敗結束
  • 遍歷text完畢時,檢查棧中是否爲空,如果爲空說明括號完全匹配,否則打印出丟失匹配的開括號。

代碼如下:

# -*- coding: utf-8 -*-
# @Author: Jiang Ji
# @Date:   2020-04-08 22:24:07
# @Last Modified by:   Jiang Ji
# @Last Modified time: 2020-04-09 09:41:40


class StackUnderflow(ValueError):
    '''自定義棧相關的異常類
    '''
    pass


class SStack:
    '''基於順序表實現的棧類
    '''

    def __init__(self):
        self._elems = []  # 用list對象 _elems存儲棧中元素

    def is_empty(self):
        return self._elems == []

    def top(self):  # 取得最後壓入的元素,即棧頂
        if self._elems == []:
            raise StackUnderflow("in SStack.pop()")
        else:
            return self._elems[-1]

    def push(self, elem):  # 壓棧
        self._elems.append(elem)

    def pop(self):  # 出棧
        if self._elems == []:
            raise StackUnderflow("in SStack.pop()")
        return self._elems.pop()


def check_parens(text):
    parens = "()[]{}"  # 所有括號字符
    open_parens = "([{"  # 開括號字符
    opposite = {")": "(", "]": "[", "}": "{"}

    def parentheses(text):
        '''括號生成器,每次調用返回text裏的下一個括號及其位置
        '''
        i, text_len = 0, len(text)
        while True:
            while i < text_len and text[i] not in parens:
                i += 1
            if i >= text_len:
                return
            yield text[i], i
            i += 1
    st = SStack()  # 保存括號的棧
    dict = {}  # 存儲括號及對應標號的字典
    for pr, i in parentheses(text):  # 對各括號和位置迭代
        dict[pr] = i
        if pr in open_parens:
            st.push(pr)  # 如果是開括號,壓棧並繼續
        elif st.pop() != opposite[pr]:  # 否則就是匹配失敗
            print("Unmatching id found at", i, "for", pr)
            return False
    #  檢查是否有丟失匹配的開括號
    if not st.is_empty():
        while not st.is_empty():
            print("Missed id found at", dict[st.top()], "for", st.top())
            st.pop()
        return False
    else:
        print("All parentheses are correctly matched.")
        return True


if __name__ == "__main__":
    text = "(da)(d}s{a"
    check_parens(text)

作者INFO
作者:JohnJim,某985本碩生,研究領域爲機器人,對機器學習、強化學習以及機器視覺等方面感興趣。
公衆號:個人公衆號【J平方】,合作公衆號【AI算法驛站】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章