4 堆疊與佇列 4.1 前言 四種基本的資料結構 (可儲存資料的容器) 陣列 (Array)、串列(List): 最基本 4 堆疊與佇列 4.1 前言 四種基本的資料結構 (可儲存資料的容器) 陣列 (Array)、串列(List): 最基本 堆疊(Stack)、佇列(Queue) 1
4.2 堆疊 特徵 出入口在相同地方:頂端 (top) 新增(push)、刪除(pop) 都要透過 top 資料進出永遠保持 “後進先出” (Last In First Out,LIFO) 的順序 歐式自助餐之餐盤堆放方式即是一個典型的堆疊結構
4.2.1 以陣列實作堆疊(ch4_stack_1.java) class Stack { int data_array[ ]; // 堆疊陣列 int top; // 堆疊頂端指標 int n; // 堆疊容量為 n } 以陣列來實作堆疊的基本動作 1.建構子 a. 產生堆疊資料陣列: 生成一個 data_array[n] 陣列, 後續新增 (push) 資料從第0個索引開始存放。 b.將堆疊頂端指標 top 設為 -1,表示目前為空堆疊
4.2.1 以陣列實作堆疊 (ch4_stack_1.java) 以陣列來實作堆疊的基本動作 (續) 2. 將資料 data 放入堆疊( push(data) ): 先判斷堆疊是否已滿,如果未滿,將 top 指標的值加 1 後,將 data_array[top] 這個陣列元素的值設為 data 3.刪除資料( pop( ) ): 若堆疊不是空的,則將頂端資料 data_array[top] 的值取出, 將 top 指標的值減 1 。 4.判斷堆疊是否滿溢 ( full( ) ): 判斷 top 指標是否等於 n-1? 5.判斷堆疊是否是空的 ( empty( ) ): 判斷 top值是否小於 0 6. 取得堆疊頂端的資料,但不刪除 ( gettop( ) ): 若堆疊不是空的,則將頂端資料 data_array[top] 的值取出
4.2.2 以串列實作堆疊(ch4_stack_2.java) class Node //節點 { int data; Node link; } 以串列來實作堆疊的基本動作 1.建構子 a. 產生 top 節點: b. 將 top.link 設為 null public class Stack_2 { Node top; }
4.2.2 以串列實作堆疊(ch4_stack_2.java) 以串列來實作堆疊的基本動作 (續) 2. 將資料 data 放入堆疊( push(data) ): 新增節點 x,將 x.data 設為 data,將 x.link 設為 top.link ,再將 top.link 設為 x 3.刪除資料( pop( ) ): 先讀取 top.link.data 的值到變數 data,再將 top.link 設為 top.link.link,最後傳回 data。 4.判斷堆疊是否滿溢 ( full( ) ): 沒有這個方法 5.判斷堆疊是否是空的 ( empty( ) ): 判斷 top.link 的值是否為 null 6. 取得堆疊頂端的資料,但不刪除 ( top( ) ): 傳回 top.link.data
4.2.3 以陣列及串列實作堆疊之比較
4.3 堆疊的應用 4.3.1 方法的呼叫 4.3.2 運算式的表示法與轉換 4.3.3 運算式求值 4.3.4 河內塔 (跳過) 4.3.5 圖形的深度優先搜尋(第 7 章再看)
4.3.1 方法的呼叫 2 3 1 4 6 5
4.3.2 運算式的表示法與轉換 算術運算式 (Arithmetic Expression) 運算元 (operand) 運算子(operator) Example: a^b-c+d*(e+f) 中 運算元:a, b, c, d, e, f 運算子:^, -, +, *, (, ) 算術運算子之優先序(當沒有括號時尤其重要) 算術運算子 優先序 ^ (次方) 3 * / 2 + - 1 ( )
4.3.2 運算式的表示法與轉換 依據運算子所在位置在運算元之前、中、後,運算式 有 3 種表示法: 前置式 (Prefix): 不能使用括號 中置式 (Infix):可以使用括號 後置式 (Postfix):不能使用括號
4.3.2 運算式的表示法與轉換 作業 範例
4.3.2 運算式的表示法與轉換 給定運算子之值,電腦 先將中值式透過堆疊 轉換成後置式,再以堆疊 的方式計算其值
利用堆疊將中置轉為後置式的做法 由左至右依序讀入每一個運算式中的字元 c 1. 如果 c 是運算元 (即範例中的 a, b, c 等), 則直接輸出到後置式 2. 如果 c 是運算子(即範例中的 +, -, *, ^ 等), 則有 3 種情形 i. c 為 ‘(‘:將 c 放入堆疊 ii. c 為 ‘)’:持續取出堆疊頂端的字元 d, 如果取出的字元 d 不是左括號 將 d 輸出至後置式 如果取出的字元 d 是左括號 停止取出堆疊頂端字元 iii. c 為其他運算子:持續取出堆疊頂端的優先序大於等於 c 的運算子 k 將 k 輸出至後置式 再將 c 放入堆疊
例 4:利用堆疊將中置式 a-b/c+(d*e)-f 轉為後置式 Note: 堆疊只存放運算子,不放運算元 運算子須先放入堆疊,然後在適當時機取出 從堆疊中取出的運算子直接輸出到後置式 例 4:利用堆疊將中置式 a-b/c+(d*e)-f 轉為後置式 步驟 讀入之字元 處理方式 堆疊 (頂端在右方) 後置式的輸出結果 空堆疊 1 a 輸出 a 2 - 將 - 放入堆疊 3 b 輸出 b ab 4 / 將 / 放入堆疊 -/ 5 c 輸出 c abc 6 + 從堆疊取出 / 並將其輸出 從堆疊取出 - 並將其輸出 將 + 放入堆疊 abc/-
練習: (a-b)/(c-d)^e a^(b+c)/d-e a+b*(c-d)^e-f 步驟 讀入之字元 處理方式 堆疊 (頂端在右方) 後置式的輸出結果 7 ( 將 ( 放入堆疊 +( abc/- 8 d 輸出 d abc/-d 9 * 將 * 放入堆疊 +(* 10 e 輸出 e abc/-de 11 ) 從堆疊取出 * 並將其輸出 從堆疊取出 ( + abc/-de* 12 - 從堆疊取出 + 並將其輸出 將 - 放入堆疊 abc/-de*+ 13 f 輸出 f abc/-de*+f 14 從堆疊取出 - 並將其輸出 空堆疊 abc/-de*+f- 練習: (a-b)/(c-d)^e a^(b+c)/d-e a+b*(c-d)^e-f
練習(課本 第4-97頁 第 19 題) 下列中置運算式之後置式表示法為何 a*b/c (a-b)/(c-d)^e a/b-c/(d+e)*f a^(b+c)/d-e a+b*(c-d)^e-f
4.3.3 運算式求值 給定運算元之值後,中置式計算原則 由左而右計算結果 優先處理括號,其餘依照運算子的優先順序處理 例如: a – b/c + (d * e) – f 3 – (12/4)+(2*6)-5 必須考慮括號及運算子優先序,相當複雜,因此電腦先將 中置式透過堆疊轉換成後置式,再以堆疊的方式計算其值
後置式運算式求值
abc/-de*+f-
練習 (課本 第4-97頁 第 20 題) 下列後置式運算式之值為何 ab*c/ ab-cd-e^/ ab/cde+/f*-
作業 寫一程式將 中置式運算式 轉換成 前置式運算式 請 擴充 ch4_postfix.java 的程式,於得到各個後置式後, 請使用者輸入各變數及其值,再計算出在這些變數給定 值的情況下該後置式的值。輸出範例: 中置運算式:a-b/c+(d*e)-f 後置運算式:abc/-de*+f- 請輸入變數之值,結束請輸入 ‘.’ > a > 2 > b > 4 > c > d > 2 > e > 3 >f >4 >. 運算式值為:2
作業第 1 題說明 中序轉前序(Converting Infix to Prefix) 將輸入字串由右至左一個一個讀入字元 運算元由右至左直接輸出,運算子也是由右至左輸出,但需考慮以 下 3-5 的情況 若讀入之運算子優先權高於堆疊最上面的運算子則推入堆疊,但讀 入之右括號有最高優先權,已推入堆疊之右括號優先權則變為最低 (推入時機) 若讀入之運算子優先權低於(含等於)堆疊最上面的運算子,彈出堆 疊之運算子,但讀入之左括號優先權最低,應持續彈出堆疊之運算 子直到遇到一右括號,括號在輸出時應自動刪除 (彈出時機) 輸入字串結束時彈出所有堆疊內之運算子