Ch 8 Stacks and Queues

advertisement
Chapter 8
Stacks
and
Queues
1
This is a
stack of
books.
2
This is a
queue.
3
Chap.8 Contents
8.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 Notation
8.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
4
8.1 Stacks
A stack
is a special list:
the only element
可 remove, access, or modify 的
是最近一次 insert 的 element
.
5
That is, the element
most recently inserted
is the next element to be removed.
Last-In,First-Out
(LIFO)
6
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
7
Top – 是最近一次 insert 的 element
Push – insert element 到 stack 中
Pop – 由 stack 中 remove top element
8
Start with an empty stack.
Push “張三”
9
Top
張三
10
Push “李四”
11
Top
李四
張三
12
Pop.
13
Top
張三
14
8.1.1 The PureStack Interface
public interface PureStack<E>
{
/** size
* 紀錄在 PureStack 有多少 elements
*
* @return PureStack 中 elements 的數量
*/
int size();
15
/** 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);
16
/** 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
17
8.1.2 實作PureStack Interface
There is an implementation in
java.util
18
public class Stack extends Vector {
…
Vector is 實質上相同於
ArrayList.
19
The push, pop and peek methods
are easily defined.
For example:
public E push (E item)
{
addElement(item);
return item;
}
20
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);
21
解決之道有三:
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. 採此法
22
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
23
寫出下列的輸出結果:
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
24
8.1.3 Stack 的應用1:
Compiler如何實作Recursive
每當有 recursive method 被呼叫,
前一次 method 資訊會被儲存,不被覆蓋.
這資訊叫 activation record.
25
Activation record 包含:
1. 呼叫 method 的 return address
2. 每個被呼叫 method 的 parameter 所對應之
argument
3. 每個被呼叫 method 的 local variable
26
Run-time stack 處理 activation records.
Push: When method is called
Pop: When execution of method
is completed
27
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
28
The following iterative method
maintains its own stack:
29
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
30
請注意,我們只儲存 n % 2 在 stack 中,
但我們無需儲存 return address.
因為此 getBinary 沒用到 recursive.
31
Exercise:
Trace the execution of the above method
after an initial call of:
getBinary (20);
show the contents of myStack.
32
8.1.4 Stack 應用 2:
轉換Infix(中置式)
到 Postfix(後置式)
在 infix 表示法中,
operator(運算子) 放置於
operands(運算元) 之間.
For example:
a+b
c – d + (e * f – g * h) / i
33
Old compilers:
Infix
Machine language
這會因為parentheses(小括號)而產生混亂.
Newer compilers:
Infix
Postfix
Machine language
34
在 postfix 表示法中, an operator 直接地放置
於他的operands之後. No parenthesis needed.
Infix
a+b
Postfix
ab+
a+b*c
abc*+
a*b+c
ab*c+
(a + b) * c
ab+c*
35
postfix 不必使用 Parentheses
很棒!
36
Let’s convert an infix string below
to a postfix string.
x–y*z
ANS: xyz*37
Postfix 保留 operands的先後順序,
so an operand can be
appended to postfix
as soon as
that operand is encountered in infix.
38
Infix
Postfix
x–y*z
x
39
Infix
Postfix
x–y*z
x
The operands for ‘-’ 尚未在 postfix,
所以 ‘ - ’ 一定要先暫存在某地方.
40
Infix
Postfix
x–y*z
xy
41
Infix
Postfix
x–y*z
xy
The operands for ‘*’ 未在postfix,
所以‘*’ 一定要暫存在某地方,
且儲存在‘-’之前.
42
Infix
Postfix
x–y*z
xyz
43
Infix
Postfix
x–y*z
xyz* –
ANS.
44
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
x*y– z
Postfix
xy
45
‘*’ 現在一定要移到 postfix 中,
因為‘*’的所有 operands 都已在 postfix 了.
接著‘-’ 要暫存起來.
在 ‘z’ 被移到 postfix 後,
‘-’ 被移到 postfix,
and we are done 我們完成了!
Infix
x*y– z
Postfix
xy*z–
(ANS.)
46
暫時儲存處是:
stack!
Here is the strategy (pseudo-code) for
maintaining the stack:
47
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
48
口訣: if Infix Greater,
then Push
49
Convert from infix to postfix:
Infix
Postfix
a+b*c/d-e
50
Infix
Postfix
a+b*c/d–e
abc*d/+e –
*
+
Operator stack
51
What about parentheses?
Left parenthesis:
Push, but with lowest 優先權.
Right parenthesis:
持續 pop 加到 postfix 直到‘(‘ popped;
丟棄‘(‘ 及 ‘)‘
52
Convert to postfix:
x * (y + z)
53
Infix
x * (y + z)
Postfix
xyz+*
*
Operator stack
54
Infix
x * (y + z – (a / b + c) * d) / e
Postfix
Operator stack
55
為了決定轉換 infix 成 postfix 的所有動
作, 我們必須知道
1) the current token in infix
2) the top token on operator stack.
56
下列的 transition matrix
說明了轉換
infix 表示式到 postfix 表示式
57
Top token on Stack
(
Infix token
Operand
)
(
+, -
*, /
Append
to
Postfix
*, /
empty
Append
to
Postfix
Append
to
Postfix
Append
to
Postfix
Pop;
Pitch ‘(‘
Push
Pop to
Postfix
Push
Pop to
Postfix
Push
Error
Push
Pop to
Postfix
Pop to
Postfix
Push
Push
Pop to
Postfix
Pop to
Postfix
Push
Push
Error
empty
+, -
Pop to
Postfix
Push
Done
58
Tokens
59
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.
60
For example:
1
2
ADD_OP
+
Operand
a
61
8.1.5 Prefix(前置式) Notation
prefix 表示法中,
operator 放置在 operands 之前.
62
Infix
a+b
Prefix
+ab
a * (b + c)
*a+bc
a*b+c
+*abc
prefix 如同 postfix, 沒有 parentheses.
63
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.
64
我們必須使用兩個 stacks:
Operator stack:
相同於 postfix stack 的使用
Operand stack:
用於儲存 operands
65
Convert from infix to prefix:
Infix
a + (b * c – d) / e
66
Infix
Prefix
a + (b * c – d) / e
+a/– *bcde
+a/– *bcde
/– *bcde
e
–*bcd
d
*bc
c
b
a
Operand
stack
*
(
+
Operator
stack
67
Exercise: Convert to Prefix
a – b + c * (d / e – (f + g))
68
8.2 Queues
A queue
is a special list:

只在尾端 insert

只在前端 delete
69
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)
70
回想一下;
STACK: (Last-In-First-Out) LIFO
71
Enqueue “張三”
72
張三
Front
Back
73
Enqueue “李四”
74
張三
Front
李四
Back
75
Enqueue “王五”
76
張三
Front
李四
王五
Back
77
Dequeue
78
李四
Front
王五
Back
79
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( );
80
/**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();
81
/** front
* returns the front element in this PureQueue
* object.
*
* @return – the element returned.
*
* @throws NoSuchElementException – if
*
PureQueue object is empty.
*
*/
E front();
} // PureQueue
82
對於 dequeue method, what is
worstTime (n)?
ANS: O(1)
83
8.2.2 Implementations of the
PureQueue Interface
為了 code re-use 的目的, the
implementation will work with an
現有的 class.
ArrayList?
LinkedList?
84
Inheritance (繼承法):
The implementation of
PureQueue is-a LinkedList
OR
Aggregation (組成法):
The implementation of
PureQueue has-a LinkedList
85
Inheritance 帶來沉重負擔:
必須 override 32 個
不適用的 super class methods.
Ex:
public E get (int index) {
throw new UnsupportedOperationException( );}
86
Heavy Inheritance Tax
在 class reuse 實務上,
被reuse的class要有完整method description
developers 清楚了解後,
再寫dummy code (如上述get) 來override
不能reuse的methods.
這是相當沉重的負擔,有如稅負,故叫
Inheritance Tax .
87
So, we’ll use aggregation:
public class LinkedListPureQueue<E>
implements PureQueue<E>
{ protected LinkedList<E> list;
88
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(); }
89
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
90
8.2.3 Computer Simulation(模擬)
SYSTEM
是由互動的部分 (interacting parts)
所組成
91
model 是 system的簡化.
建構model 是為了研究 system
92
Physical model: 不同於 system 只在於其
scale(規模) 或 intensity(強度).
Examples: pre-season (美職棒季前賽)
93
Mathematical model:
A set of equations,
variables, and
assumptions
94
A
500’
D
200’
?
500’
B
400’
C
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?
95
徒手解決 math model 不可行, 所以發展
computer program 來計算.
Computer simulation:
The development of computer programs to
solve math models.
96
Develop
System
Computer
Model
Verify
Run
Interpretation
Output
Decipher
97
如果 model 詮釋的 不能對應到 system 的行
為, 表示 model 不合
就換另一個 model!
98
Feedback(回饋):
本身的 output 會影響自己
Here, the model is affected by its output.
99
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
100
carWash
• Minimal waiting time is 0 min.
• Maximal waiting time:10 min*5car= 50 min
arrival
queue
departure
to queue
from queue
Wash Station
car
car
car
car
car
101
Average waiting time =
sum of waiting times / number of cars
In a given minute,
a departure is processed
before an arrival.
102
如果一台車到達時,
剛好沒有車正在洗
(no car is waiting),
那這台車就會立即進入 wash station.
如果有車正在洗,他必須等待.
Sentinel (結束訊號) is 999.
103
System test 1:
8
11
11
13
14
16
16
20
999
104
Time
8
11
11
13
14
16
16
18
20
28
38
48
58
68
Event
Waiting Time
Arrival
0 (arri 8)
Arrival
(arri 11)
Arrival
(arri 11)
Arrival
(arri 13)
Arrival
(arri 14)
Arrival
(arri 16)
Arrival (Overflow)
Departure 18 - 11 = 7
7 (arri 11,deq 18)
Arrival
(arri 20)
Departure
17 (arri 11)
Departure
25 (arri 13)
Departure
34 (arri 14)
Departure
42 (arri 16)
Departure
48 (arri 20)
Average waiting time = 173.0 minutes / 7 cars
= 24.7 minutes per car
本表為本程式輸出
105
Exercise:
Given the following arrival times,
determine the average waiting time:
4, 8, 12, 16, 23, 999 (the sentinel)
106
Design of CarWash class
107
/** CarWash
* 初始化此 CarWash object.
*/
public CarWash()
108
/** 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)
109
/** finishUp
* wash 所有尚未 wash 的車子
*/
public void finishUp()
/* getResults
* returns 所有 arrival 與 departures 紀錄
* 及 average waiting time.
*/
public LinkedList<String> getResults()
110
Fields?
First, we’ll decide what variables
will be needed, and
then choose the fields from them.
111
PureQueue<Car> carQueue;
112
carQueue 中每個 element 是 Car
What information about a car
do we need?
113
為何單獨設計 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.
114
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()
115
To calculate the average waiting time:
int
numberOfCars,
sumOfWaitingTimes;
116
To get the sum of the waiting times:
int
currentTime,
waitingTime;
waitingTime = currentTime – car.getArrivalTime();
計算車子進 wash station 前的 waiting time.
117
The simulation will be event-based:
Is the next event
an arrival or
a departure?
118
// 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;
119
Finally,
// to store the:
//
arrivals,
//
departures, and
//
average waiting time
//
LinkedList<String> results;
120
A rule of thumb (經驗之談) is that:
a field should be needed in
most of the class’s public methods.
121
Fields (Data structure):
PureQueue<Car> carQueue;
LinkedList<String> results;
int currentTime,
waitingTime,
sumOfWaitingTimes,
numberOfCars,
nextDepartureTime;//10000 if no car is being washed
122
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
123
public void process (int nextArrivalTime)
{
if (nextArrivalTime < currentTime)
throw new IllegalArgumentException();
while (nextArrivalTime >= nextDepartureTime)
processDeparture();
processArrival (nextArrivalTime);
}
124
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*/
125
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
126
public class Car{
protected int arrivalTime;
public Car(){}//default constructor,
//for the sake of sub-classses of Car
public Car (int nextArrivalTime){
arrivalTime=nextArrivalTime;
}// constructor with int parameter
public int getArrivalTime(){
return arrivalTime;
}/*getArrivalTime*/ }/*Car*/
127
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) );
128
Exercise:
Assume that meanArrivalTime is 3.
If Math.log (1 – randomDouble) = –0.6
and currentTime = 25,
When will the next arrival occur?
129
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.
130
Download