在數據結構與算法領域,棧的操作與應用、卡特蘭計數問題、表達式解析值得關注。以下詳細解釋:
1.基礎結構:進棧順序
1)進棧順序的基本概念
進棧順序(Push Order)是指元素按照特定順序被壓入棧中的過程。棧遵循後進先出(LIFO)原則,即:最後壓入的元素最先被彈出。理解進棧順序的推算是分析棧操作和解決相關問題的基礎。
2)棧的操作規則
棧支持兩種基本操作:
- Push(壓棧):將元素添加到棧的頂部。
- Pop(彈棧):移除並返回棧頂的元素。
任何合法的棧操作序列必須滿足:在彈出某個元素之前,該元素必須已被壓入棧中,且未被提前彈出。
3)推算進棧順序的步驟
給定一個棧的輸入序列和輸出序列,可以通過模擬棧的操作來驗證其合法性:
- 初始化一個空棧和一個指向輸入序列開頭的指針;
- 遍歷輸出序列中的每個元素,檢查是否可以通過壓棧或彈棧操作得到該元素;
- 若當前棧頂元素與輸出序列的當前元素匹配,則彈棧並移動到輸出序列的下一個元素;
- 若不匹配,則從輸入序列中壓入下一個元素到棧中,直到匹配或輸入序列耗盡;
- 若輸入序列耗盡且棧頂元素仍不匹配,則輸出序列不合法。
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,但1和2被壓在棧底,無法提前彈出。
此序列不合法。
5)合法序列的數學性質
對於長度為 的輸入序列,合法的輸出序列數為卡特蘭數(Catalan Number):
例如,
6)實際應用場景
- 函數調用棧:程序執行時函數的調用和返回順序必須符合棧的邏輯。
- 表達式求值:中綴表達式轉後綴表達式時需處理運算符的優先級和結合性。
- 瀏覽器歷史:頁面的前進和後退操作類似棧的壓入和彈出。
通過模擬棧的操作和驗證輸出序列的合法性,可以解決多數與棧順序相關的問題。
2.原理:卡特蘭數
1)卡特蘭數的定義
卡特蘭數(Catalan numbers)是組合數學中重要的數列,常用於解決計數問題。其第n項通常記作,遞推公式為:
初始條件為。前幾項為:1, 1, 2, 5, 14, 42, 132…
2)遞推關係
卡特蘭數滿足以下遞推關係:
例如。
3)常見應用場景
a.合法的括號序列
n對括號能組成種合法的匹配序列。例如n=3時有5種:
①((())), ② (()()), ③(())(), ④()(()), ⑤()()()
b.二叉樹形態計數
n個節點可以構成種不同的滿二叉樹結構(每個節點有0或2個子節點)。
c.凸多邊形三角劃分
n+2邊的凸多邊形用不相交對角線劃分為三角形,有種方法。
d.不相交的弦
圓上2n個點兩兩連線不相交的方案數為。
4)生成函數推導
卡特蘭數的生成函數為:
通過解方程,得到閉式:
另一版本,可以直接計算卡特蘭數:
5)實際計算示例
計算:
- 組合數形式:
- 遞推方式:如前述
- 直接公式:
6)與其他數列關係
與二項式係數密切相關:
這個差分形式體現了"合法路徑"與"非法路徑"的計數原理。
3.解析:逆波蘭表達式
1)逆波蘭表達式簡介
逆波蘭表達式(Reverse Polish Notation,RPN)是一種數學表達式的書寫方法,其特點是將運算符寫在操作數的後面。例如,常見的表達式 (1 + 2) * 3 在逆波蘭表達式中寫為 1 2 + 3 *。這種表示法無需括號即可明確運算順序,適合棧結構處理。
2)逆波蘭表達式的求值步驟
- 初始化棧
使用一個棧存儲操作數,遍歷逆波蘭表達式的每個元素。 - 處理操作數
當遇到數字時,將其壓入棧中。 - 處理運算符
當遇到運算符時,從棧頂彈出兩個操作數進行計算,並將結果壓回棧中。注意操作數的順序(先彈出的是右操作數)。 - 最終結果
遍歷結束後,棧頂元素即為表達式的結果。
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]。 - 遇到
"+",彈出1和2,計算2 + 1 = 3,壓入棧 → 棧:[3]。 - 遍歷
"3",壓入棧 → 棧:[3, 3]。 - 遇到
"*",彈出3和3,計算3 * 3 = 9,壓入棧 → 棧:[9]。 - 最終結果為
9。
注意事項
- 除法處理:逆波蘭表達式的除法需向零取整(如
6 / -4 = -1)。 - 操作數順序:減法和除法需注意操作數的順序(如
a - b和a / b)。 - 有效性驗證:輸入需確保是合法的逆波蘭表達式(操作數與運算符匹配)。