1 chapter 8 stacks and queues. 2 this is a stack of books

130
1 Chapter 8 Stacks and Queues

Post on 20-Dec-2015

218 views

Category:

Documents


0 download

TRANSCRIPT

1

Chapter 8

Stacks and

Queues

2

This is a stack of books.

3

This is a queue.

4

Chap.8 Contents8.1 Stacks 8.1.1 The PureStack Interface 8.1.2 Implementations of the PureStack Interface 8.1.3 Stack Application 1: How Compilers Implement Recursion 8.1.4 Stack Application 2: Converting from Infix to Postfix 8.1.5 Prefix Notation8.2 Queues 8.2.1 The PureQueue Interface 8.2.2 Implementations of the PureQueue Interface 8.2.3 Computer Simulation 8.2.4 Queue Application: A Simulated Car Wash

5

A stack is a special list: the only element 可 remove, access, or modify 的 是最近一次 insert的 element .

8.1 Stacks

6

That is, the element most recently inserted

is the next element to be removed.

Last-In,First-Out (LIFO)

7

Object-Oriented (O-O) Terms

• Stack, Queue 是特別的 list. 以 O-O 術語 , 它們 EXTEND ( 延伸 )

list (ArrayList 或 LinkedList)

General concepts ( 通用觀念 ) are Super class such as ArrayList

Specialized concepts ( 專用觀念 ) are Sub class such as Stack

8

Top – 是最近一次 insert的 element Push – insert element到 stack中 Pop – 由 stack中 remove top element

9

Start with an empty stack.

Push “張三”

10

Top

張三

11

Push “李四”

12

Top

李四

張三

13

Pop.

14

Top

張三

15

public interface PureStack<E> { /** size * 紀錄在 PureStack有多少 elements * * @return PureStack中 elements 的數量

*/ int size();

8.1.1 The PureStack Interface

16

/** isEmpty * 記錄此 PureStack object是否內部沒有任何 element. * * @return true – 如果此 PureStack object 沒有任何 * elements; 否則, return false. */

boolean isEmpty();

/** push * inserts a 指定的 element

* on the top of this PureStack object. *

* The averageTime(n) is constant and * worstTime(n) is O(n).

* * @param element – the element to be pushed. * */ void push (E element);

17

/** pop * removes the top element from this PureStack object. * * @return – the element removed.

* @throws NoSuchElementException * – 如果此 PureStack is empty.

*/ E pop(); /** peek * returns the top element on this PureStack object. * * @return – the element returned. * @throws NoSuchElementException

* – 如果此 PureStack object is empty. */ E peek(); } // interface PureStack

18

There is an implementation in

java.util

8.1.2 實作 PureStack Interface

19

public class Stack extends Vector { …

Vector is 實質上相同於

ArrayList.

20

The push, pop and peek methods

are easily defined. For example: public E push (E item)

{ addElement(item); return item; }

21

But NO Vector methods are overridden(覆蓋) 所以可呼叫 vector的任何 method 這會干擾到 stack的定義! For example, it is NOT allowed to remove a stack element at index 7:

myStack.remove (7);

22

解決之道有三: 1. Inherit (繼承) from ArrayList 或 LinkedList

Ugh! 唉阿! Too many overrides. 2. Use an array

protected E[ ] data; protected int top;

Then, top 將會是 array的尾端 (不是前端 index 0)不方便.

3.Aggregate (組成) an ArrayList or LinkedList Yes, and all method definitions are one-liners. 採此法

23

public class LinkedListPureStack <E> { protected LinkedList<E> list; // aggregate a list

public LinkedListPureStack // copy constructor (LinkedListPureStack<E> otherStack)

{ list = new LinkedList<E> (otherStack.list); } public void push (E element) { list.add (element); } // push … } // LinkedListPureStack

24

寫出下列的輸出結果 :LinkedListPureStack<Integer> myStack =

new LinkedListPureStack<Integer>( );

for (int i = 0; i < 10; i++) myStack.push (i * i);

while (!myStack.isEmpty( )) System.out.println (myStack.pop( ));

ANS: 81 (9*9), 64 (8*8), 49, 36, 25, 16, 9, 4, 1, 0

25

8.1.3 Stack 的應用 1: Compiler 如何實作 Recursive

每當有 recursive method 被呼叫, 前一次 method資訊會被儲存,不被覆蓋. 這資訊叫 activation record.

26

Activation record 包含: 1. 呼叫 method的 return address 2. 每個被呼叫 method的 parameter 所對應之

argument 3. 每個被呼叫 method的 local variable

27

       

Run-time stack 處理 activation records.

Push: When method is called

Pop: When execution of method is completed 

28

Decimal to Binary: Ex: get binary “101” from decimal “5” public static String getBinary (int n) { if (n < 0) throw new IllegalArgumentException(); if (n <= 1) return Integer.toString (n); return getBinary(n / 2) + Integer.toString(n % 2); } // method getBinary

29

The following iterative method maintains its own stack:

30

public static String getBinary (int n) {

ArrayStack<Integer> myStack = new ArrayStack<Integer>();

String binary = new String(); If(n<0)throw new IllegalArgumentException( );

myStack.push (n % 2); while (n > 1) { n /= 2; myStack.push (n % 2); }

while(!myStack.isEmpty()) binary+=myStack.pop();

return binary; } // end of getBinary

31

請注意,我們只儲存 n % 2 在 stack中, 但我們無需儲存 return address. 因為此 getBinary 沒用到 recursive.

32

Exercise: Trace the execution of the above method after an initial call of:

getBinary (20);

show the contents of myStack.

33

8.1.4 Stack 應用 2: 轉換 Infix( 中置式 ) 到 Postfix( 後置式 )

在 infix 表示法中 , operator(運算子 ) 放置於operands(運算元 ) 之間 .

For example: a + b

c – d + (e * f – g * h) / i

34

Old compilers:

Infix Machine language

這會因為 parentheses( 小括號 ) 而產生混亂 .

Newer compilers:

Infix Postfix Machine language

35

在 postfix 表示法中 , an operator 直接地放置於他的 operands之後 . No parenthesis needed.

Infix

Postfix

a + b

ab+

a + b * c

abc*+

a * b + c

ab*c+

(a + b) * c

ab+c*

36

postfix 不必使用 Parentheses

很棒 !

37

Let’s convert an infix string below to a postfix string. 

  x – y * z

ANS: xyz*-

38

Postfix 保留 operands 的先後順序 ,

so an operand can be appended to postfix as soon as that operand is encountered in infix.

39

Infix Postfix

x – y * z x

40

Infix Postfix

x – y * z x

The operands for ‘-’ 尚未在 postfix,

所以 ‘ - ’ 一定要先暫存在某地方 .

41

Infix Postfix

x – y * z xy

42

Infix Postfix

x – y * z xy

The operands for ‘*’ 未在 postfix, 所以‘ *’ 一定要暫存在某地方 ,

且儲存在‘ -’ 之前 .

43

Infix Postfix

x – y * z xyz

44

Infix Postfix

x – y * z xyz* –

ANS.

45

As another test case, we start with x*y-z. After moving ‘x’ to postfix,

‘*’ is temporarily saved, and then

‘y’ 被加到 postfix.

What happens when ‘-’ is accessed?

Infix Postfix

x * y – z xy

46

‘*’ 現在一定要移到 postfix 中, 因為‘*’的所有 operands都已在 postfix了. 接著‘-’ 要暫存起來. 在 ‘z’ 被移到 postfix後, ‘-’ 被移到 postfix,

and we are done 我們完成了! Infix Postfix

x * y – z xy*z– (ANS.)

47

暫時儲存處是 :

stack!

Here is the strategy (pseudo-code) for

maintaining the stack:

48

for each operator in infix: loop until operator pushed: if operator stack is empty, Push

else if infix operator has greater precedence than top operator on stack,

Push else Pop and append to postfix endif endif endLoop endFor

49

口訣 : if Infix Greater, then Push

50

Convert from infix to postfix:

Infix Postfix

a + b * c / d - e

51

Infix Postfix

a + b * c / d – e abc*d/+e –

*

+

Operator stack

52

What about parentheses? Left parenthesis: Push, but with lowest 優先權. Right parenthesis: 持續 pop加到 postfix 直到‘(‘ popped; 丟棄‘(‘ 及 ‘)‘

53

Convert to postfix:

x * (y + z)

54

Infix Postfix x * (y + z) xyz+*

*

Operator stack

55

Infix Postfix x * (y + z – (a / b + c) * d) / e

Operator stack

56

為了決定轉換 infix 成 postfix的所有動作, 我們必須知道

1) the current token in infix 2) the top token on operator stack.

57

下列的 transition matrix 說明了轉換

infix 表示式到 postfix 表示式

58

Top token on Stack

( +, - *, / empty

Operand

)

( +, -

*, /

empty

Append Append Append Append to to to to Postfix Postfix Postfix Postfix

Pop; Pop to Pop to Error Pitch ‘(‘ Postfix Postfix Push Push Push Push Push Pop to Pop to Push Postfix Postfix Push Push Pop to Push Postfix Error Pop to Pop to Done Postfix Postfix

Infi

x to

ken

59

Tokens

60

A token 是 program最小有意義單元 (smallest meaningful unit).

Each token has two parts:

1. A generic part, for the category(分類) of the token;

2. A specific part,

to access the characters in the token.

61

For example:

ADD_OP +

Operand a

1 2

62

prefix 表示法中, operator 放置在 operands之前.

8.1.5 Prefix( 前置式 ) Notation

63

Infix Prefix a + b +ab a * (b + c) *a+bc a * b + c +*abc

prefix 如同 postfix, 沒有 parentheses.

64

Whenever opt is popped from operator stack, opd1 and then opd2 are popped

from operand stack. The string opt + opd2 + opd1

is pushed onto operand stack.

Note: opd2 was pushed before opd1.

65

我們必須使用兩個 stacks:

Operator stack: 相同於 postfix stack的使用

Operand stack:

用於儲存 operands

66

Convert from infix to prefix: Infix

a + (b * c – d) / e

67

Infix Prefix a + (b * c – d) / e +a/– *bcde +a/– *bcde /– *bcde e –*bcd d *bc c * b ( a +

Operand Operator stack stack

68

Exercise: Convert to Prefix

a – b + c * (d / e – (f + g))

69

A queue is a special list:

只在尾端 insert

只在前端 delete

8.2 Queues

70

Enqueue –在尾端 insert element Dequeue –在前端 delete element Front – return 前端 element (的 reference)

Queue的 first element inserted will be the first element deleted:

First-In, First-Out (FIFO)

71

回想一下;

STACK: (Last-In-First-Out) LIFO

72

Enqueue “ 張三”

73

張三

Front Back

74

Enqueue “ 李四”

75

張三

Front

李四

Back

76

Enqueue “ 王五”

77

王五張三

Front

李四

Back

78

Dequeue

79

王五

Front

李四

Back

80

8.2.1 The PureQueue Interface

public interface PureQueue<E> {

//size returns elements 數量在此 PureQueue object. int size( );

// isEmpty returns true // if this PureQueue object has no elements. boolean isEmpty( );

81

/**enqueue * inserts 一個指定的 element 在此 PureQueue object. * 的尾端 The averageTime(n) is * constant and worstTime(n) is O(n). * * @param element – the element to be appended. */ void enqueue (E element);

/** dequeue * removes 在此 PureQueue * object最前端的 element. * * @return – the element removed. * @throws NoSuchElementException – if this * PureQueue object is empty. */ E dequeue();

82

/** front * returns the front element in this PureQueue * object. * * @return – the element returned. * * @throws NoSuchElementException – if * PureQueue object is empty. * */ E front(); } // PureQueue

83

對於 dequeue method, what is

worstTime (n)? ANS: O(1)

84

為了 code re-use 的目的, the implementation will work with an 現有的 class.

ArrayList?

LinkedList?

8.2.2 Implementations of the PureQueue Interface

85

Inheritance (繼承法):

The implementation of

PureQueue is-a LinkedList

OR Aggregation (組成法):

The implementation of

PureQueue has-a LinkedList

86

Inheritance 帶來沉重負擔: 必須 override 32 個 不適用的 super class methods.

Ex: public E get (int index) { throw new UnsupportedOperationException( );}

87

Heavy Inheritance Tax

在 class reuse 實務上, 被 reuse的 class 要有完整 method description

developers 清楚了解後, 再寫 dummy code ( 如上述 get) 來 override

不能 reuse的 methods.

這是相當沉重的負擔,有如稅負,故叫 Inheritance Tax .

88

So, we’ll use aggregation: public class LinkedListPureQueue<E> implements PureQueue<E> { protected LinkedList<E> list;

89

public LinkedListPureQueue() {list = new LinkedList<E>(); }

public void enqueue (E element) { {list.addLast (element); // same as list.add (element);}

public E dequeue() {return list.removeFirst(); }

90

Determine the output from the following:

LinkedListPureQueue<Integer> myQueue = new LinkedListPureQueue<Integer>();

for (int i = 0; i < 10; i++) myQueue.enqueue (i * i);

while (!myQueue.isEmpty( )) System.out.println (myQueue.dequeue( ));

ANS: 0(0*0),1(1*1),4, 9, 16, 25, 36, 49, 64, 81

91

8.2.3 Computer Simulation( 模擬 )

SYSTEM

是由互動的部分 (interacting parts)

所組成

92

model 是 system 的簡化 .

建構 model 是為了研究 system

93

Physical model: 不同於 system 只在於其 scale(規模) 或 intensity(強度).

Examples: pre-season (美職棒季前賽)

94

Mathematical model: A set of equations,

variables, and assumptions

95

A 500’ D ? 200’ 500’ C B 400’ E Assumptions: Angle ADC = angle BCD BEC forms a right triangle DCE forms a straight line Line segment AB parallel to DC Distance from A to B?

96

徒手解決 math model 不可行, 所以發展computer program 來計算. Computer simulation: The development of computer programs to solve math models.

97

Develop System Computer Model Verify Run Interpretation Output Decipher

98

如果 model詮釋的 不能對應到 system 的行為, 表示 model不合

就換另一個 model!

99

Feedback(回饋): 本身的 output會影響自己 Here, the model is affected by its output.

100

8.2.4 Queue Application: A Simulated Car Wash

Analysis: 1) One wash station 2) 10 minutes for each car to get washed 3) At any time, at most 5 cars

waiting to be washed; any others:

turned away and not counted

101

carWash

• Minimal waiting time is 0 min.

• Maximal waiting time:10 min*5car= 50 min

car car car car car

queuearrival

departurefrom queue

to queue

Wash Station

102

Average waiting time =

sum of waiting times / number of cars In a given minute,

a departure is processed before an arrival.

103

如果一台車到達時, 剛好沒有車正在洗

(no car is waiting), 那這台車就會立即進入 wash station. 如果有車正在洗,他必須等待. Sentinel (結束訊號) is 999.

104

System test 1: 8

11 11 13 14 16 16 20

999

105

Time Event Waiting Time 8 Arrival 0 (arri 8) 11 Arrival (arri 11) 11 Arrival (arri 11) 13 Arrival (arri 13) 14 Arrival (arri 14) 16 Arrival (arri 16) 16 Arrival (Overflow)

18 Departure 18 - 11 = 7 7 (arri 11,deq 18) 20 Arrival (arri 20) 28 Departure 17 (arri 11) 38 Departure 25 (arri 13) 48 Departure 34 (arri 14) 58 Departure 42 (arri 16) 68 Departure 48 (arri 20)

Average waiting time = 173.0 minutes / 7 cars = 24.7 minutes per car 本表為本程式輸出

106

Exercise: Given the following arrival times, determine the average waiting time: 4, 8, 12, 16, 23, 999 (the sentinel)

107

Design of CarWash class

108

/** CarWash * 初始化此 CarWash object. */ public CarWash()

109

/** process * * @param nextArrivalTime下一輛車的到達時間

* the time when the next arrival will occur. * * @throws IllegalArgumentException –

* If nextArrivalTime is less than the current time. */ public void process (int nextArrivalTime)

110

/** finishUp * wash所有尚未 wash的車子 */ public void finishUp() /* getResults * returns 所有 arrival與 departures 紀錄 * 及 average waiting time.

*/ public LinkedList<String> getResults()

111

Fields? First, we’ll decide what variables

will be needed, and then choose the fields from them.

112

PureQueue<Car> carQueue;

113

carQueue 中每個 element是 Car What information about a car

do we need?

114

為何單獨設計 Car class? 為日後維修方便 We have a Car class for the sake of later modifications to the problem. For example, the cost of a wash might

depend on the number of axles.

115

Car class• /* Car • * 初始化 Car object • * 為指定的下次到達時間• */ • public Car (int nextArrivalTime)

/* getArrivalTime• /* 記錄 the just dequeued car 的 arrival time. • * @return the arrival time of this car • */• public int getArrivalTime()

116

To calculate the average waiting time:

int numberOfCars, sumOfWaitingTimes;

117

To get the sum of the waiting times:

int currentTime, waitingTime; waitingTime = currentTime – car.getArrivalTime();

計算車子進 wash station前的 waiting time.

118

The simulation will be event-based: Is the next event

an arrival or a departure?

119

// time of next arriving car to the queue int nextArrivalTime;

// time of next departing car from the queue

// it is 10000 if no car being washed // so next event will be an arrival int nextDepartureTime;

120

Finally, // to store the: // // arrivals, // departures, and // average waiting time LinkedList<String> results;

121

A rule of thumb (經驗之談) is that: a field should be needed in most of the class’s public methods.

122

Fields (Data structure): PureQueue<Car> carQueue; LinkedList<String> results; int currentTime, waitingTime, sumOfWaitingTimes, numberOfCars, nextDepartureTime;//10000 if no car is being washed

123

public CarWash() { carQueue<Car> = new LinkedListPureQueue<Car>(); results = new LinkedList<String>(); results.add (“Time Event Waiting Time”); currentTime = 0; waitingTime = 0; numberOfCars = 0; sumOfWaitingTimes = 0; nextDepartureTime = 10000; } // constructor

124

public void process (int nextArrivalTime) { if (nextArrivalTime < currentTime) throw new IllegalArgumentException(); while (nextArrivalTime >= nextDepartureTime) processDeparture(); processArrival (nextArrivalTime); }

125

protected void processArrival (int nextArrivalTime){ currentTime = nextArrivalTime; results.add (Integer.toString (currentTime) + “\tArrival”);

if (carQueue.size() == 5) results.add (“ (Overflow)\n”); else{ /* not overflow */ numberOfCars++; if/*no car being wash*/(nextDepartureTime == 10000) nextDepartureTime = currentTime + /*wash time*/10; else /* wait in the queue */ carQueue.enqueue (new Car (nextArrivalTime)); results.add ("\n"); }/*else*/ } /*end of processArrival*/

126

protected void processDeparture() { currentTime = nextDepartureTime; results.add (Integer.toString (currentTime) + “\tDeparture\t\t” + Integer.toString (waitingTime) + "\n"); if (!carQueue.isEmpty()) { /* carQueue is not empty */ Car car = carQueue.dequeue(); waitingTime = currentTime – car.getArrivalTime(); sumOfWaitingTimes += waitingTime; nextDepartureTime = currentTime + /*wash time*/ 10; }

else { /* carQueue is empty */ waitingTime = 0; nextDepartureTime = 10000; } //else } // end of processDeparture

127

public class Car{protected int arrivalTime;public Car(){}//default constructor,

//for the sake of sub-classses of Carpublic Car (int nextArrivalTime){

arrivalTime=nextArrivalTime;}// constructor with int parameter

public int getArrivalTime(){return arrivalTime;

}/*getArrivalTime*/ }/*Car*/

128

arrival times 不一定要從 file讀進來, Instead 相反的, we will read in:

int meanArrivalTime; // the average time between arrivals

Then, using

double randomDouble = random.nextDouble( );

to calculate

int timeTillNext = (int)Math.round (-meanArrivalTime *

Math.log (1 - randomDouble) );

129

Exercise: Assume that meanArrivalTime is 3. If Math.log (1 – randomDouble) = –0.6

and currentTime = 25,

When will the next arrival occur?

130

timeTillNext = (int)Math.round (-meanArrivalTime * Math.log (1 - randomDouble));

= (int)Math.round (-3 * -0.6)

= (int)Math.round (1.8)

= 2

So, the next arrival will be at

time 25+2 = 27.