Data Structures Chapter 3 Stacks and Queues Instructor: Ching Chi Lin 林 清 池 助 理 教 授 chingchi.lin@gmail.com Department of Computer Science and Engineering National Taiwan Ocean University
Outline Stacks ( 堆 疊 ) Queues( 佇 列 ) A Mazing Problem ( 迷 宮 問 題 ) Evaluation of Expressions ( 運 算 式 計 算 ) 2
Stacks Definition: A stack is an ordered list in which insertions (push/add) and deletions (pop/remove) are made at on end called top. ( 堆 疊 一 種 有 序 的 串 列, 僅 在 頂 端 進 行 插 入 和 刪 除 的 動 作 ) The last element inserted into a stack is the first element removed. Last In First Out list, LIFO. ( 後 進 先 出 ) top top top top top B C B D C B C B A A A A A D push push push pop 3
Stack Array Implementation The easiest way to implement this ADT is by using a one dimensional array. ( 使 用 陣 列 來 實 作 堆 疊 最 容 易 ) a n-1... a 2 a 1 a 0 a 0 a 1 a 2... a n 2 a n 1 4
Functions for Stacks 1/2 Create Stack Create an empty stack whose maximum size is MAX_STACK_SIZE #define MAX_STACK_SIZE 100 /*maximum stack size*/ typedef struct{ int key; /* other fields */ } element; element stack[max_stack_size]; Int top = 1; IsEmpty Return TRUE if stack is empty and FALSE otherwise top < 0 5
Functions for Stacks 2/2 IsFull Return TRUE if stack is full and FALSE otherwise top >= MAX_STACK_SIZE 1; Add Insert item into top of the stack Delete Remove and return the item on the top of the stack 6
Program 3.1 Add to a stack void add (int *top, element item) { /* add an item to the global stack */ if (*top >=MAX_STACK_SIZE 1) { stack_full(); return; } stack[++*top]=item; } 7
Program 3.2 Delete from a stack element delete (int *top) { /* return the top element from the stack */ if (*top == 1) return stack_empty(); /* returns an error key */ return stack[(*top) ]; } 8
An Application of Stack: Stack Frame of Function Call stack frame: activation record ( 活 動 記 錄 ) fp: a pointer to the current stack frame previous frame pointer return address a1 fp fp local variables previous frame pointer previous frame pointer return address main return address main system stack before a1 is invoked system stack after a1 is invoked 9
Outline Stacks ( 堆 疊 ) Queues( 佇 列 ) A Mazing Problem ( 迷 宮 問 題 ) Evaluation of Expressions ( 運 算 式 計 算 ) 10
Queues Definition: A queue is an ordered list in which insertions take place at one end and all deletions take place at the opposite end. ( 佇 列 一 種 有 序 的 串 列, 插 入 發 生 在 串 列 的 一 端, 刪 除 發 生 另 一 端 ) The first element inserted into a queue is the first element removed. First In First Out list, FIFO. ( 先 進 先 出 ) add add delete rear front A rear front B A rear front C B A rear front C B A 11
Functions for Queues 1/2 Create Queue Create an empty queue #define MAX_QUEUE_SIZE 100 /* Maximum queue size */ typedef struct{ int key; /* other fields */ } element; element queue[max_queue_size]; int rear = 1; int front = 1; IsEmptyQ Return TRUE if the queue is empty and FALSE otherwise front == rear; 12
Functions for Queues 2/2 IsFullQ Return TRUE if the queue is full and FALSE otherwise rear == MAX_STACK_SIZE 1; AddQ Insert item at rear of queue and return queue DeleteQ Remove and return the item at front of queue 13
Program 3.3 Add to a queue void addq (int *rear, element item) { /* add an item to the queue */ if (*rear == MAX_QUEUE_SIZE 1) { queue_full(); return; } queue[++*rear] = item; } 14
Program 3.4 Delete from a queue element deleteq (int *front, int rear) { /* remove element at the front of the queue */ if (*front == rear) return queue_empty(); /*return an error key */ return queue[++*front]; } 15
Insertion and Deletion From a Sequential Queue Job scheduling The queue gradually shift to right. ( 佇 列 逐 漸 地 向 右 移 動 ) If rear index equals MAX_QUEUE_SIZE 1, suggesting that the queue is full. We should move the entire queue to the left: O(MAX_QUEUE_SIZE). front rear Q[0] Q[1] Q[2] Q[3] Comments 1 1 queue is empty 1 0 J1 Job 1 is added 1 1 J1 J2 Job 2 is added 1 2 J1 J2 J3 Job 3 is added 0 2 J2 J3 Job 1 is deleted 1 2 J3 Job 2 is deleted 16
Circular Queues 1/2 Straight line array >circle Initial circular queue: front = rear = 0; front: one position counterclockwise from the first element in the queue. ( 逆 時 鐘 第 一 個 元 素 的 前 一 個 位 置 ) rear: current end of the queue. ( 目 前 最 後 的 位 置 ) 3 4 3 4 3 4 2 5 2 J2 J3 5 2 5 1 6 1 J1 6 1 J3 J2 J1 6 0 7 front =0; rear=0 0 7 front =0; rear=3 0 7 front =5; rear=0 17
Circular Queues 2/2 A circular queue of size MAX_QUEUE_SIZE will be permitted to hold at most MAX_QUEUE_SIZE 1 elements. ( 最 多 只 能 儲 存 MAX_QUEUE_SIZE 1 元 素 ) The addition of such an element will result in front = rear and won t be able to distinguish between an empty and a full queue. ( 否 則 無 法 辨 別 它 是 一 個 空 佇 列 或 是 一 個 滿 載 佇 列 ) 3 4 3 4 2 J2 J3 J4 J5 5 2 J5 J6 J7 5 1 J1 J7 J6 6 1 J4 J3 J2 J1 6 0 7 front =0; rear=7 0 7 front =5; rear=4 18
Program 3.5: Add to A Circular Queue void addq (int front, int *rear, element item) { /* add an item to the queue */ *rear = (*rear+1)% MAX_QUEUE_SIZE; if (front == *rear) { queue_full(rear); /* reset rear and print error */ return; } queue[*rear] = item; } 19
Program 3.6: Delete From a Circular Queue element deleteq (int *front, int rear) { element item; /* remove front element from the queue and put it in item */ if (*front == rear) return queue_empty(); /* queue_empty returns an error key */ *front = (*front+1)% MAX_QUEUE_SIZE; return queue[*front]; } 20
Outline Stacks ( 堆 疊 ) Queues( 佇 列 ) A Mazing Problem ( 迷 宮 問 題 ) Evaluation of Expressions ( 運 算 式 計 算 ) 21
A Mazing Problem Example: find the path 0: paths 1: barriers Entrance 0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 1 1 1 1 0 1 1 0 1 1 0 0 1 1 0 1 0 0 1 0 1 1 1 1 1 1 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 1 0 Exit 22
Next Move Allowable moves NW [i 1][j 1] W [i][j 1] SW [i+1][j 1] N [i 1][j] X [i][j] S [i+1][j] typedef struct { short int vert; short int horiz; } offsets; offsets move [8]; NE [i 1][j+1] E [i][j+1] SE [i+1][j+1] Table of moves Name Dir Move[dir].vert Move[dir].horiz N 0 1 0 NE 1 1 1 E 2 0 1 SE 3 1 1 S 4 1 0 SW 5 1 1 W 6 0 1 NW 7 1 1 next_row = row + move[dir].vert; next_col = col + move[dir].horiz; 23
Initial Attempt at A Maze Traversal Algorithm A second two dimensional array, mark, records the maze positions already checked. ( 使 用 另 一 個 二 維 陣 列 紀 錄 已 檢 查 過 的 位 置 ) Use a stack to save current path and direction. 24 ( 使 用 一 個 堆 疊 紀 錄 目 前 的 路 徑 和 方 向 ) We can return to it and try another path if we take a hopeless path. The stack size is at most m n, which is the number of positions in the maze. #define MAX_STACK_SIZE 100 /*maximum stack size*/ typedef struct { short int row; short int col; short int dir; } element; element stack[max_stack_size];
Program 3.7: Initial Maze Algorithm Initialize a stack to the maze s entrance coordinates and direction to north; while (stack is not empty){ /* move to position at top of stack */ <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) { /* legal move and haven t been there */ mark[next_row][next_col] = 1; /* save current position and direction */ add <row, col, dir> to the top of the stack; row = next_row; col = next_col; dir = north; } } Complexity: O(mn) } printf( No path found\n ); 25
Program 3.8: Maze Search Function 1/2 void path (void) { /* output a path through the maze if such a path exists */ int i, row, col, next_row, next_col, dir, found = FALSE; element position; mark[1][1] = 1; top =0; stack[0].row = 1; stack[0].col = 1; stack[0].dir = 1; while (top > 1 &&!found) { position = delete(&top); row = position.row; col = position.col; dir = position.dir; while (dir < 8 &&!found) { /*move in direction dir */ next_row = row + move[dir].vert; next_col = col + move[dir].horiz; if (next_row==exit_row && next_col==exit_col) found = TRUE; else if (!maze[next_row][next_col] &&!mark[next_row][next_col] { mark[next_row][next_col] = 1; 26
Program 3.8: Maze Search Function 2/2 } position.row = row; position.col = col; position.dir = ++dir; add(&top, position); row = next_row; col = next_col; dir = 0; } else ++dir; } } if (found) { printf( The path is :\n ); printf( row col\n ); for (i = 0; i <= top; i++) printf( %2d%5d, stack[i].row, stack[i].col); printf( %2d%5d\n, row, col); printf( %2d%5d\n, EXIT_ROW, EXIT_COL); } else printf( The maze does not have a path\n ); 27
Outline Stacks ( 堆 疊 ) Queues( 佇 列 ) A Mazing Problem ( 迷 宮 問 題 ) Evaluation of Expressions ( 運 算 式 計 算 ) 28
Expressions 1/2 The representation and evaluation of expressions is of great interest to computer scientists. ( 計 算 機 科 學 家 對 於 運 算 式 的 表 示 法 與 計 算 方 法 感 到 有 趣 ) Example: ((rear+1==front) ((rear==max_queue_size 1) &&!front)) operators : ==, +,,, &&,! ( 運 算 符 號 ) operands: rear, front, MAX_QUEUE_SIZE ( 運 算 元 ) parentheses: (, ) ( 括 號 ) 29
Expressions 2/2 Why expressions are important? For example, 1: 9 + 3 * 5 =? 2: 9 3 2 =? Case 1a: 9 + 3 * 5 = 24 Case 2a: 9 3 2 = 4 Case 1b: 9 + 3 * 5 = 60 Case 2b: 9 3 2 = 8 The difference between case 1a & case 1b Precedence rule ( 優 先 權 法 則 ) The difference between case 2a & case 2b Associative rule ( 關 連 性 法 則 ) Within any programming language, there is a precedence hierarchy that determines the order in which we evaluate operators. ( 任 何 程 式 語 言 都 有 一 種 用 來 決 定 計 算 符 號 先 後 順 序 的 優 先 權 等 級 ) 30
Precedence Hierarchy for C How to generate the machine instructions corresponding to a given expression? ( 給 定 一 個 運 算 式 如 何 產 生 相 對 應 的 電 腦 指 令?) precedence rule + associative rule ( 優 先 權 法 則 + 關 連 性 法 則 ) The associativity column indicates how we evaluate operators with the same precedence. ( 相 同 優 先 權 如 何 計 算 ) 31
Evaluating Postfix Expressions 1/2 The standard way of writing expressions is known as infix notation. ( 運 算 式 標 準 的 寫 法 稱 中 序 表 示 法 ) Place a binary operator in between its two operands. Ex: a + b It is not the one used by compilers to evaluate expressions. Instead compilers typically use postfix. ( 編 譯 器 用 後 序 表 示 法 ) Infix 2 + 3 * 4 a * b + 5 (1 + 2 ) * 7 a * b / c ((a / (b c + d)) * (e a)* c a / b c + d * e a* c Postfix 234*+ ab*5+ 12+7* ab*c/ abc d+/ea *c* ab/c de*+ac* 32
Evaluating Postfix Expressions 2/2 Evaluating postfix expressions is much simpler than the evaluation of infix expressions. ( 計 算 後 序 運 算 式 較 容 易 ) There are no parentheses and precedence to consider. To evaluate an expression we make a single left to right scan of it. We can evaluate an expression easily by using a stack. For example, the input is nine character string 6 2/3 4 2*+ 33
Postfix Evaluating : The Representations of Postfix Expression And Stack Expression is represented as a character array. The operators are +,, *, / and %. The operands are 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. The operands are stored on a stack of type int. The stack is represented by a global array accessed only through top. The declarations are: #define MAX_STACK_SIZE 100 /* maximum stack size */ #define MAX_EXPR_SIZE 100 /* max size of expression */ typedef enum {lparen, rparen, plus, minus, times, divide, mod, eos, operand} precedence; int stack[max_stack_size]; /* global stack */ char expr[max_expr_size]; /* input string */ 34
35
Program 3.10: Function to get a token from the input string precedence get_token(char *symbol, int *n) { /* get the next token, symbol is the character representation, which is returned, the token is represented by its enumerated value, which is returned in the function name */ } 36 *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 \0 : return eos; default : return operand; /* no error checking, default is operand */ }
Infix to Postfix 1/4 Algorithm 1 Ex: a / b c + d * e a * c Step1: fully parenthesize the expression. ( 將 運 算 式 加 上 刮 號 ) ((((a/ b) c)+(d*e)) (a*c)) Step2: move all binary operators so that they replace their corresponding right parentheses. ( 將 運 算 符 號 取 代 其 相 對 應 的 右 刮 號 ) ((((ab/c (de*+ac* Step3: delete all parentheses. ab/c de*+ac* 37
Infix to Postfix 2/4 Algorithm 2 Scan string from left to right ( 由 左 而 右 掃 瞄 ) Operands are taken out immediately ( 遇 到 運 算 元 立 即 輸 出 ) Operators are taken out of the stack as long as their in stack precedence (isp) is higher than or equal to the incoming precedence (icp) of the new operator ( 運 算 符 號 的 isp 大 於 等 於 新 的 運 算 符 號 的 icp 時 立 即 將 它 自 堆 疊 中 推 出 ) If token == right parenthesis, unstack tokens until we reach the corresponding left parenthesis. ( 遇 到 )" 將 堆 疊 中 運 算 元 推 出 直 到 遇 到 相 對 應 的 (") 38
Infix to Postfix 3/4 a + b * c Token a + b Stack [0] [1] [2] + + to p 1 0 0 outpu t a a ab op ( ) + isp 0 19 12 icp 20 19 12 * + * 1 ab 12 12 c eos + * 1 1 abc abc*+ * / 13 13 13 13 % 13 13 eos 0 0 39
Infix to Postfix 4/4 a * (b + c) * d toke n a * ( Stack [0] [1] [2] * * ( top 1 0 1 output a a a op ( ) + isp 0 19 12 icp 20 19 12 b * ( 1 ab 12 12 + c ) * * ( + * ( + * * 2 2 0 0 ab abc abc+ abc+* * / % 13 13 13 13 13 13 d * 0 abc+*d eos 0 0 eos 1 abc+*d* 40
Complexity: Θ(n) The total time spent here is Θ(n) as the number of tokens that get stacked and unstacked is linear in n, where n is the number of tokens in the expression.