在數據結構與算法領域,棧的操作與應用、卡特蘭計數問題、表達式解析值得關注。以下詳細解釋:

1.基礎結構:進棧順序

1)進棧順序的基本概念

進棧順序(Push Order)是指元素按照特定順序被壓入棧中的過程。棧遵循後進先出(LIFO)原則,即:最後壓入的元素最先被彈出。理解進棧順序的推算是分析棧操作和解決相關問題的基礎。

2)棧的操作規則

棧支持兩種基本操作:

  • Push(壓棧):將元素添加到棧的頂部。
  • Pop(彈棧):移除並返回棧頂的元素。

任何合法的棧操作序列必須滿足:在彈出某個元素之前,該元素必須已被壓入棧中,且未被提前彈出。

3)推算進棧順序的步驟

給定一個棧的輸入序列和輸出序列,可以通過模擬棧的操作來驗證其合法性:

  1. 初始化一個空棧和一個指向輸入序列開頭的指針;
  2. 遍歷輸出序列中的每個元素,檢查是否可以通過壓棧或彈棧操作得到該元素;
  3. 若當前棧頂元素與輸出序列的當前元素匹配,則彈棧並移動到輸出序列的下一個元素;
  4. 若不匹配,則從輸入序列中壓入下一個元素到棧中,直到匹配或輸入序列耗盡;
  5. 若輸入序列耗盡且棧頂元素仍不匹配,則輸出序列不合法。

4)示例分析

假設輸入序列為 [1, 2, 3, 4, 5],輸出序列為 [4, 5, 3, 2, 1]

  • 壓入 1, 2, 3, 4,彈出 4
  • 壓入 5,彈出 5
  • 彈出 3, 2, 1
    此輸出序列合法。

若輸出序列為 [4, 3, 5, 1, 2]

  • 彈出 4, 3 後,棧中剩餘 [1, 2]
  • 彈出 5 時需壓入 5,但 12 被壓在棧底,無法提前彈出。
    此序列不合法。

5)合法序列的數學性質

對於長度為 數據結構與算法 05 棧與逆波蘭表達式_#數據結構 的輸入序列,合法的輸出序列數為卡特蘭數(Catalan Number):
數據結構與算法 05 棧與逆波蘭表達式_#算法_02
例如,數據結構與算法 05 棧與逆波蘭表達式_#彙編_03

6)實際應用場景

  1. 函數調用棧:程序執行時函數的調用和返回順序必須符合棧的邏輯。
  2. 表達式求值:中綴表達式轉後綴表達式時需處理運算符的優先級和結合性。
  3. 瀏覽器歷史:頁面的前進和後退操作類似棧的壓入和彈出。

通過模擬棧的操作和驗證輸出序列的合法性,可以解決多數與棧順序相關的問題。

2.原理:卡特蘭數

1)卡特蘭數的定義

卡特蘭數(Catalan numbers)是組合數學中重要的數列,常用於解決計數問題。其第n項通常記作數據結構與算法 05 棧與逆波蘭表達式_#筆記_04,遞推公式為:
數據結構與算法 05 棧與逆波蘭表達式_逆波蘭表達式_05
初始條件為數據結構與算法 05 棧與逆波蘭表達式_#算法_06。前幾項為:1, 1, 2, 5, 14, 42, 132…

2)遞推關係

卡特蘭數滿足以下遞推關係:
數據結構與算法 05 棧與逆波蘭表達式_#數據結構_07
例如數據結構與算法 05 棧與逆波蘭表達式_#數據結構_08

3)常見應用場景

a.合法的括號序列
n對括號能組成數據結構與算法 05 棧與逆波蘭表達式_#筆記_04種合法的匹配序列。例如n=3時有5種:
①((())), ② (()()), ③(())(), ④()(()), ⑤()()()

b.二叉樹形態計數
n個節點可以構成數據結構與算法 05 棧與逆波蘭表達式_#筆記_04種不同的滿二叉樹結構(每個節點有0或2個子節點)。

c.凸多邊形三角劃分
n+2邊的凸多邊形用不相交對角線劃分為三角形,有數據結構與算法 05 棧與逆波蘭表達式_#筆記_04種方法。

d.不相交的弦
圓上2n個點兩兩連線不相交的方案數為數據結構與算法 05 棧與逆波蘭表達式_#筆記_04

4)生成函數推導

卡特蘭數的生成函數為:
數據結構與算法 05 棧與逆波蘭表達式_#算法_13

通過解方程數據結構與算法 05 棧與逆波蘭表達式_#彙編_14,得到閉式:
數據結構與算法 05 棧與逆波蘭表達式_#筆記_15
另一版本,可以直接計算卡特蘭數:
數據結構與算法 05 棧與逆波蘭表達式_#筆記_16

5)實際計算示例

計算數據結構與算法 05 棧與逆波蘭表達式_#彙編_17

  1. 組合數形式:數據結構與算法 05 棧與逆波蘭表達式_#算法_18
  2. 遞推方式:如前述數據結構與算法 05 棧與逆波蘭表達式_#算法_19
  3. 直接公式:數據結構與算法 05 棧與逆波蘭表達式_#算法_20

6)與其他數列關係

與二項式係數密切相關:
數據結構與算法 05 棧與逆波蘭表達式_#筆記_21
這個差分形式體現了"合法路徑"與"非法路徑"的計數原理。

3.解析:逆波蘭表達式

1)逆波蘭表達式簡介

逆波蘭表達式(Reverse Polish Notation,RPN)是一種數學表達式的書寫方法,其特點是將運算符寫在操作數的後面。例如,常見的表達式 (1 + 2) * 3 在逆波蘭表達式中寫為 1 2 + 3 *。這種表示法無需括號即可明確運算順序,適合棧結構處理。

2)逆波蘭表達式的求值步驟

  1. 初始化棧
    使用一個棧存儲操作數,遍歷逆波蘭表達式的每個元素。
  2. 處理操作數
    當遇到數字時,將其壓入棧中。
  3. 處理運算符
    當遇到運算符時,從棧頂彈出兩個操作數進行計算,並將結果壓回棧中。注意操作數的順序(先彈出的是右操作數)。
  4. 最終結果
    遍歷結束後,棧頂元素即為表達式的結果。

3)示例代碼實現

以下是逆波蘭表達式求值的 Python 實現:

def eval_rpn(tokens):
    stack = []
    for token in tokens:
        if token in "+-*/":
            b = stack.pop()
            a = stack.pop()
            if token == '+':
                stack.append(a + b)
            elif token == '-':
                stack.append(a - b)
            elif token == '*':
                stack.append(a * b)
            elif token == '/':
                stack.append(int(a / b))  # 注意除法向零取整
        else:
            stack.append(int(token))
    return stack.pop()

示例解析

以逆波蘭表達式 ["2", "1", "+", "3", "*"] 為例:

  • 遍歷 "2""1",壓入棧中 → 棧:[2, 1]
  • 遇到 "+",彈出 12,計算 2 + 1 = 3,壓入棧 → 棧:[3]
  • 遍歷 "3",壓入棧 → 棧:[3, 3]
  • 遇到 "*",彈出 33,計算 3 * 3 = 9,壓入棧 → 棧:[9]
  • 最終結果為 9

注意事項

  • 除法處理:逆波蘭表達式的除法需向零取整(如 6 / -4 = -1)。
  • 操作數順序:減法和除法需注意操作數的順序(如 a - ba / b)。
  • 有效性驗證:輸入需確保是合法的逆波蘭表達式(操作數與運算符匹配)。