--- tags: 資料結構, --- # 資料結構 第三章 堆疊與佇列 ![](https://i.imgur.com/f9ov4Ae.jpg) ## 一、堆疊抽象資料型態(The Stack Abstract Data Type) ### (一)定義堆疊操作 【變數設定】 for all stack belong to Stack, item belong to element, max_stack_size belong to positive integer 1、Stack Create(max_stack_size):創造一個空的堆疊(容量為max_stack_size)。 2、Boolean IsFull(stack, max_stack_size):判斷堆疊是否滿了,滿了回傳True,否則為False。 3、Boolean IsEmpty(stack):判斷堆疊是否為空,空了回傳True(判斷可用空間=最大空間),否則為False。 4、Stack Add(stack, item):前提假設堆疊未滿,將Data插入堆疊最上端(Top),前提假設不成立(代表堆疊已滿)則無法再插入Data並回傳堆疊已滿(Stack_Full)。 5、Element Delete(stack):前提假設堆疊不為空,則將pop堆疊在上端的Data,前提假設不成立(堆疊為空)無資料刪除,故回傳Stack_Empty。 ### (二)堆疊插入刪除圖式如下: ![reference link](https://i.imgur.com/r6J1P1J.jpg) ### (三)呼叫函式後系統使用堆疊(System stack after function call) 系統將紀錄參數值、區域變數、返回位址存入堆疊 ![](https://i.imgur.com/AB9s8tz.jpg) ### (四)程式碼(插入、刪除) void add(int *top,element item) { if(*top >= Max_Stack_Size-1) //第一格index為零 { stack_full(); return; } stack[++*top] = item; } void delete(int *top) { if(*top == -1) //若迴圈下無{}則只會執行一行 return stack_empty(); return stack[(*top)--]; } ## 二、佇列抽象資料型態(The Queue Abstract Data Type) ### (一)定義佇列操作 【變數設定】 for all queue belong to Queue, item belong to element, max_queue_size belong to positive integer 1、Queue CreateQ(max_queue_size):創造一個佇列(容量為max_queue_size)。 2、Boolean IsFullQ(queue, max_queue_size):判斷佇列是否滿了(資料個數=最大空間),滿了回傳Queue_Full,否則回傳False。 3、Boolean IsEmptyQ(queue):判斷佇列是否為空(可用空間=最大空間),是則回傳True,否則回傳False。 4、Queue AddQ(queue, item):前提假設佇列不為滿,則將Data由前端(front)加入佇列中,前提假設不成立則回傳Queue_Full。 5、Element DeleteQ(queue):前提假設佇列不為空,則將Data由尾端(Rear)移出佇列。 ### (二)佇列插入刪除圖式如下: ![](https://i.imgur.com/UhzLzAK.jpg) void addq(int *rear, element item) { if(*rear == Max_Queue_Size-1) { queue_full(); return; } queue[++*rear]= item; } element deleteq(int *front, int rear) { if(*front == rear) return queue_empty(); return queue[++*front]; } 延伸問題: 當front = -1 時,代表queue為空尚有n個空間,當rear == n-1時,queue不一定就是滿的,若先執行n次插入再執行n次刪除(如下圖所示)。 ![](https://i.imgur.com/gUBIO5o.png) ### (三)佇列改善(環狀佇列)圖示如下: ![](https://i.imgur.com/lF4hzYj.jpg) ![](https://i.imgur.com/60LEg5C.jpg) #### 特色: 1.Full和empty條件相同 2.Queue[0...n-1]中有n格空間,但需要犧牲一格空間,故能使用空間只有n-1個 ### (程式碼) 【環狀佇列】 void addq(int front, int *rear, element item) { *rear = (*rear+1) % Max_Queue_Size; if (front == *rear) { queue_full(rear); return; } queue[*rear] = item; } element deleteq(int *front, int rear) { element item; if(*front == rear) return queue_empty(); *front = (*front+1) % Max_Queue_Size; return queue[*front]; } ## 三、迷宮問題(A Mazing Problem) ### (一)迷宮示意圖 將迷宮想像成矩陣,從起點(左上)走至終點(右下),每次行走時要判斷往哪個方向走,如下圖所示可分成八個方位。 ![](https://i.imgur.com/KZsXjkg.jpg) 每次行走時記錄下位置,若走到死路無法繼續前進(則pop Stack)返回至原本的點,換其他路徑繼續前進。 ![](https://i.imgur.com/NG2eSKj.png) ### (二)程式碼 #define typedef MAX-STACK-SIZE 100 struct { short int row; short int col; short int dir; } element; element stack[MAX-STACK-SIZE]; initialize a stack to the maze's entrance coordinates and direction to north; while (stack is not empty) { <row,col,dir> = delete from top of stack; while((there are more moves from current position)) { <next_row, next_col> = = coordinates of next move; dir = direction of move; if ( (next_row == EXIT_ROW) && (next_col == EXIT-COL)) success; if((maze[next_row][next_col] == 0 && mark[next_row][next_col] == 0)) { mark[next—row] [next—col] = 1; add <row,col,dir> to the top of the stack; row = next_row; col = next_col; dir = north; } } } ## 四、值的表示方式(Evaluation of Expressions) 我們從小使用的運算皆是中置式,舉例如下: ![](https://i.imgur.com/ReBnMMf.jpg) 中置式不論是要轉給電腦方便運算的後置式等,運算子的優先權高低(含左右結合表)如下圖: ![](https://i.imgur.com/mfAq3TI.jpg) ### (一)後置式表示法(Evaluatng Postfix Expressions) 以上圖為例後置式表示對照圖如下: ![](https://i.imgur.com/l2TQWmP.jpg) ![](https://i.imgur.com/RKLg3oG.jpg) 補充:前置式 | Infix | Postfix | -------- | --------| | 2+3*4 | +2*34| |a*b+5|+*ab5 |(1+2)*7|*+127| |a*b/c|/*abc| |((a/(b-c+d))*(e-a)*c)|**/a+ -bcd-eac |a/b-c+d*e-a*c|-+ -/abc*ac ### (二)中置式轉後置式(Infix to Postfix) 中置式轉後置式,利用stack操作,下圖為stack轉換過程: ![](https://i.imgur.com/kdl4462.jpg) 細分解: 將(a+b*c)轉成後置式 | 步驟 | step1 | step2 | step3 | step4 | step5 | step6 | step7 | | -------- | ---------------------------------------------------------- | -------- |:-----------------------:| ----- | ----- | ----- | ----- | | scan | scan"(" :左括號在stack外優先權最高,但在stack內優先權最低 | scan"a" | scan"+" 優先權:+ > ( | sacn"b" | scan"*" | scan"c" | scan")" | | 運作 | push "("置stack | print"a" |push"+"置stack | print"b" |push"*"置satck 優先權:* > + | print"c" | 遇到")"將stack 連續pop直到遇到"("並將pop出來的值印出 | | 目前輸出 | | a | a | ab | ab |abc | abc*+| ![](https://i.imgur.com/6D2n4e5.png) 【程式碼】 int eval(void) { precedence token; char symbol; int op1, op2; int n = 0; int top = -1; token = get_token(&symbol, &n); while(token != eos) { if (token== operand) add(&top, symbol_'0') else { return result to the stack op2 = delete(&top); op1 = delete(&top); switch(token) { case "+":add(&top, op1+op2); break; case "-":add(&top, op1-op2); break; case "*":add(&top, op1*op2); case "/":add(&top, op1/op2) case "%":add(&top, op1%op2) } } token = get_token(&symbol, &n); } return delete(&top); } precedence get_token(char *symbol, int *n) { *symbol = expr[(*n)++]; switch(*symbol) { case "(": return lparen; case ")": return rparen; case "+": return plus; case "-": return minus; case "/": return divide; case "*": return times; case "%": return mod; case " ": return eos; default : return operand; } } ## 五、多堆疊與佇列(Multiple Stacks And Queues) ![](https://i.imgur.com/aD0VINF.jpg) ![](https://i.imgur.com/1AlKT4K.jpg) ### (一)使用stack製作Queue ![](https://i.imgur.com/fT864SP.png) 1.create createQ(n) { createS(n); } --- 2.addQ AddQ(Q, item) { if(isFull(s)) print "Queue滿"; else push(s,item); } #概念:將Stack的Top視為Queue的rear --- ![](https://i.imgur.com/YPAGleb.png) 3.delete Delete(Q) { if(isEmpty(s)) print "Queue為空"; else { T:stack; while(Not Isempty(s)) { y=pop(s); push(T,y); } item = Pop(T); while(Not Isempty(T))do { y=Pop(T); push(S,y); } } } --- ### (二)利用Queue製作Stack ![](https://i.imgur.com/PH18oNt.png) 1.create create S(n) { create Q(n) } --- 2.push push(S, item) { if (is Full (Q)) return "stack已滿" else Add Q(Q,item) } --- ![](https://i.imgur.com/XN1hvHf.png) 3.pop pop(s) { if (is empty(Q)) return "stack是空的" else { n = rear-front+1; for(i=1 n-1 ) { y=DeleteQ(Q); add Q(Q,y); } item = deleteQ(Q); } } > 參考資料:Fundamentals of Data Structures in C by Ellis Horowitz, Sartaj Sahni, Susan Anderson-Freed