Download Algorithms ・ 1.3 B

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Algorithms
Stacks and queues
R OBERT S EDGEWICK | K EVIN W AYNE
Fundamental data types.
・Value: collection of objects.
・Operations: insert, remove, iterate, test if empty.
・Intent is clear when we insert.
・Which item do we remove?
1.3 B AGS , QUEUES, AND S TACKS
‣ stacks
stack
push
‣ resizing arrays
Algorithms
F O U R T H
E D I T I O N
R OBERT S EDGEWICK | K EVIN W AYNE
http://algs4.cs.princeton.edu
pop
‣ queues
queue
dequeue
enqueue
‣ generics
‣ iterators
‣ applications
Stack. Examine the item most recently added.
LIFO = "last in first out"
Queue. Examine the item least recently added.
FIFO = "first in first out"
2
Client, implementation, interface
Separate interface and implementation.
Ex: stack, queue, bag, priority queue, symbol table, union-find, .…
Benefits.
・Client can't know details of implementation
1.3 B AGS, Q UEUES, AND STACKS
⇒
client has many implementation from which to choose.
・Implementation can't know details of client needs
‣ stacks
⇒
many clients can re-use the same implementation.
・
・Performance:
‣ resizing arrays
Design: creates modular, reusable libraries.
Algorithms
use optimized implementation where it matters.
R OBERT S EDGEWICK | K EVIN W AYNE
Client: program using operations defined in interface.
http://algs4.cs.princeton.edu
Implementation: actual code implementing operations.
Interface: description of data type, basic operations.
3
‣ queues
‣ generics
‣ iterators
‣ applications
Stack API
Stack test client
Warmup API. Stack of strings data type.
Read strings from standard input.
push
・If string equals "-", pop string from stack and print.
・Otherwise, push string onto stack.
pop
push
pop
public class StackOfStrings
public static void main(String[] args)
{
StackOfStrings stack = new StackOfStrings();
while (!StdIn.isEmpty())
{
String s = StdIn.readString();
create an empty stack
StackOfStrings()
insert a new string onto stack
void push(String item)
remove and return the string
most recently added
String pop()
if (s.equals("-")) StdOut.print(stack.pop());
else
stack.push(s);
is the stack empty?
boolean isEmpty()
}
number of strings on the stack
int size()
}
% more tobe.txt
to be or not to - be - - that - - - is
% java StackOfStrings < tobe.txt
to be not that or be
Warmup client. Reverse sequence of strings from standard input.
5
Stack: linked-list representation
6
Stack pop: linked-list implementation
Maintain pointer to first node in a linked list; insert/remove from front.
StdIn
StdOut
be
be
insert at front
of linked list
first
not
not
to
to
remove from front
of linked list
to
-
that
not
be
be
-
String item = first.item;
be
not
to
delete first node
null
or
or
-
save item to return
to
null
to
not
be
or
not
or
not
or
inner class
to
null
be
or
be
or
be
private class Node
{
String item;
Node next;
to
null
be
}
to
null
first = first.next;
first
or
to
null
to
null
first
or
to
null
be
be
be
to
null
return saved item
return item;
to
null
or
be
that
or
to
null
be
Removing the first node in a linked list
to
null
7
8
Stack push: linked-list implementation
Stack: linked-list implementation in Java
public class LinkedStackOfStrings
{
private Node first = null;
save a link to the list
Node oldfirst = first;
oldfirst
first
inner class
or
be
private class Node
{
String item;
Node next;
}
to
null
create a new node for the beginning
public boolean isEmpty()
{ return first == null;
first = new Node();
private class Node
{
String item;
Node next;
}
oldfirst
first
or
be
to
null
first.item = "not";
first.next = oldfirst;
not
or
be
}
public void push(String item)
{
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
}
set the instance variables in the new node
first
private inner class
(access modifiers don't matter)
public String pop()
{
String item = first.item;
first = first.next;
return item;
}
to
null
}
Inserting a new node at the beginning of a linked list
9
10
Stack: linked-list implementation performance
Stack: array implementation
Proposition. Every operation takes constant time in the worst case.
Array implementation of a stack.
Proposition. A stack with N items uses ~ 40 N bytes.
・Use array s[] to store N items on stack.
・push(): add new item at s[N].
・pop(): remove item from s[N-1].
node object (inner class)
public class Node
{
String item;
inner class
Node next;
...
private class
Node
}
{
String item;
Node next;
}
40 bytes
object
overhead
16 bytes (object overhead)
extra
overhead
8 bytes (inner class extra overhead)
s[]
8 bytes (reference to String)
item
references
next
8 bytes (reference to Node)
to
be
or
not
to
be
null
null
null
null
0
1
2
3
4
5
6
7
8
9
N
40 bytes per stack node
capacity = 10
Remark. This accounts for the memory for the stack
(but not the memory for strings themselves, which the client owns).
Defect. Stack overflows when N exceeds capacity. [stay tuned]
11
12
Stack: array implementation
Stack considerations
Overflow and underflow.
public class FixedCapacityStackOfStrings
{
private String[] s;
private int N = 0;
・Underflow: throw exception if pop from an empty stack.
・Overflow: use resizing array for array implementation. [stay tuned]
a cheat
(stay tuned)
Null items. We allow null items to be inserted.
public FixedCapacityStackOfStrings(int capacity)
{ s = new String[capacity]; }
Loitering. Holding a reference to an object when it is no longer needed.
public boolean isEmpty()
{ return N == 0; }
public String pop()
{ return s[--N]; }
public void push(String item)
{ s[N++] = item; }
loitering
public String pop()
{ return s[--N]; }
use to index into array;
then increment N
}
public String pop()
{
String item = s[--N];
s[N] = null;
return item;
}
this version avoids "loitering":
garbage collector can reclaim memory
only if no outstanding references
decrement N;
then use to index into array
13
14
Stack: resizing-array implementation
Problem. Requiring client to provide capacity does not implement API!
Q. How to grow and shrink array?
First try.
1.3 B AGS, Q UEUES, AND S TACKS
・push(): increase size of array s[] by 1.
・pop(): decrease size of array s[] by 1.
‣ stacks
‣ resizing arrays
Algorithms
R OBERT S EDGEWICK | K EVIN W AYNE
http://algs4.cs.princeton.edu
‣ queues
‣ generics
Too expensive.
・Need to copy all items to a new array.
・Inserting first N items takes time proportional to 1 + 2 + … + N ~
‣ iterators
N 2 / 2.
infeasible for large N
‣ applications
Challenge. Ensure that array resizing happens infrequently.
16
Stack: resizing-array implementation
Stack: amortized cost of adding to a stack
"repeated doubling"
Q. How to grow array?
Cost of inserting first N items. N + (2 + 4 + 8 + … + N) ~ 3N.
A. If array is full, create a new array of twice the size, and copy items.
1 array access
per push
k array accesses to double to size k
(ignoring cost to create new array)
public ResizingArrayStackOfStrings()
{ s = new String[1]; }
public void push(String item)
{
if (N == s.length) resize(2 * s.length);
s[N++] = item;
}
cost (array accesses)
128
private void resize(int capacity)
{
String[] copy = new String[capacity];
for (int i = 0; i < N; i++)
copy[i] = s[i];
s = copy;
}
one gray dot
for each operation
64
128
red dots give cumulative average
3
0
see next slide
number of push() operations
0
128
Amortized cost of adding to a Stack
Consequence. Inserting first N items takes time proportional to N (not N 2 ).
17
18
Stack: resizing-array implementation
Stack: resizing-array implementation
Q. How to shrink array?
Q. How to shrink array?
First try.
Efficient solution.
・
・pop():
・push():
・pop():
push(): double size of array s[] when array is full.
halve size of array s[] when array is one-half full.
Too expensive in worst case.
・
・Each operation takes time proportional to N.
to
be
or
not
N = 4
to
be
or
not
N = 5
to
be
or
not
N = 4
to
be
or
not
halve size of array s[] when array is one-quarter full.
public String pop()
{
Consider push-pop-push-pop-… sequence when array is full.
N = 5
double size of array s[] when array is full.
String item = s[--N];
s[N] = null;
if (N > 0 && N == s.length/4) resize(s.length/2);
return item;
to
null
null
null
to
null
null
null
}
Invariant. Array is between 25% and 100% full.
19
20
Stack: resizing-array implementation trace
Stack resizing-array implementation: performance
Amortized analysis. Average running time per operation over
push()
pop()
N
a.length
0
1
2
3
4
5
6
7
Proposition. Starting from an empty stack, any sequence of M push and
0
1
null
to
1
1
to
be
2
2
to
be
or
3
4
to
be
or
null
not
4
4
to
be
or
not
to
a worst-case sequence of operations.
a[]
pop operations takes time proportional to M.
5
8
to
be
or
not
to
null
null
null
to
4
5
8
8
to
to
be
be
or
or
not
not
null
be
null
null
null
null
null
null
-
be
4
8
to
be
or
not
null
null
null
null
-
not
3
8
to
be
or
null
null
null
null
null
be
that
4
8
to
be
or
that
null
null
null
null
-
that
3
8
to
be
or
null
null
null
null
null
-
or
2
4
to
be
null
null
-
be
1
2
to
null
2
2
to
is
is
best
worst
amortized
construct
1
1
1
push
1
N
1
pop
1
N
1
size
1
1
1
doubling and
halving operations
Trace of array resizing during a sequence of push() and pop() operations
order of growth of running time
for resizing stack with N items
21
22
Stack resizing-array implementation: memory usage
Stack implementations: resizing array vs. linked list
Proposition. Uses between ~ 8 N and ~ 32 N bytes to represent a stack
Tradeoffs. Can implement a stack with either resizing array or linked list;
with N items.
client can use
Nodeinterchangeably.
oldfirst = first; Which one is better?
save a link to the list
・~ 8 N when full.
・~ 32 N when one-quarter full.
public class ResizingArrayStackOfStrings
{
private String[] s;
private int N = 0;
…
}
oldfirst
Linked-list implementation.
first
or
8
24
8
4
bytes
bytes
bytes
bytes
be
・Every operation takes constant time in the worst case.
extra time and space to deal with the links.
・Usescreate
a new node for the beginning
(reference to array)
(array overhead)
× array size
(int)
to
null
first = new Node();
Resizing-array implementation.
oldfirst
・Every operation takes constant amortized time.
・Less wasted space.
4 bytes (padding)
first
or
be
to
null
set the instance variables in the new node
N = 4
to= "not";
be
or
first.item
first.next = oldfirst;
first
Remark. This accounts for the memory for the stack
(but not the memory for strings themselves, which the client owns).
23
not
or
not
null
be
null
null
null
to
null
Inserting a new node at the beginning of a linked list
24
Queue API
enqueue
public class QueueOfStrings
create an empty queue
QueueOfStrings()
1.3 B AGS , QUEUES, AND S TACKS
void enqueue(String item)
‣ stacks
is the queue empty?
boolean isEmpty()
‣ queues
Algorithms
remove and return the string
least recently added
String dequeue()
‣ resizing arrays
number of strings on the queue
int size()
‣ generics
insert a new string onto queue
‣ iterators
R OBERT S EDGEWICK | K EVIN W AYNE
dequeue
‣ applications
http://algs4.cs.princeton.edu
26
Queue: linked-list representation
Queue dequeue: linked-list implementation
Maintain pointer to first and last nodes in a linked list;
save item to return
insert/remove from opposite ends.
StdIn
StdOut
to
to
null
be
to
first
to
not
to
to
to
remove from front
of linked list
to
-
-
be
be
be
be
or
delete first node
first = first.next;
be
null
or
-
String item = first.item;
or
not
not
be
be
be
or
or
not
to
inner class
last
or
or
not
not
to
be
null
private class Node
{
String item;
Node next;
insert at end
of linked list
or
null
not
null
not
to
be
or
null
first
last
to
be
}
or
null
to
null
return saved item
to
null
to
last
first
return item;
be
null
Removing the first node in a linked list
be
null
Remark. Identical code to linked-list stack pop().
27
28
Queue enqueue: linked-list implementation
Queue: linked-list implementation in Java
save a link to the last node
public class LinkedQueueOfStrings
{
private Node first, last;
Node oldlast = last;
oldlast
private class Node
{ /* same as in StackOfStrings */
last
first
to
be
or
null
public boolean isEmpty()
{ return first == null;
create a new node for the end
inner class
oldlast
first
to
be
last
or
null
}
public void enqueue(String item)
{
Node oldlast = last;
last = new Node();
last.item = item;
last.next = null;
if (isEmpty()) first = last;
else
oldlast.next = last;
}
last = new Node();
last.item = "not";
private class Node
{
String item;
Node next;
}
}
not
null
special cases for
empty queue
link the new node to the end of the list
public String dequeue()
{
String item = first.item;
first
= first.next;
if (isEmpty()) last = null;
return item;
}
oldlast.next = last;
oldlast
first
to
be
last
or
not
null
}
Inserting a new node at the end of a linked list
29
30
Queue: resizing array implementation
Array implementation of a queue.
・Use array q[] to store items in queue.
・enqueue(): add new item at q[tail].
・dequeue(): remove item from q[head].
・Update head and tail modulo the capacity.
・Add resizing array.
1.3 B AGS, Q UEUES, AND STACKS
‣ stacks
‣ resizing arrays
q[]
null
null
the
best
of
times
null
null
null
null
0
1
2
3
4
5
6
7
8
9
head
tail
Algorithms
capacity = 10
R OBERT S EDGEWICK | K EVIN W AYNE
http://algs4.cs.princeton.edu
Q. How to resize?
31
‣ queues
‣ generics
‣ iterators
‣ applications
Parameterized stack
Parameterized stack
We implemented: StackOfStrings.
We implemented: StackOfStrings.
We also want: StackOfURLs, StackOfInts, StackOfVans, ….
We also want: StackOfURLs, StackOfInts, StackOfVans, ….
Attempt 1. Implement a separate stack class for each type.
Attempt 2. Implement a stack with items of type Object.
・Rewriting code is tedious and error-prone.
・Maintaining cut-and-pasted code is tedious and error-prone.
・Casting is required in client.
・Casting is error-prone: run-time error if types mismatch.
StackOfObjects s = new StackOfObjects();
@#$*! most reasonable approach until Java 1.5.
Apple a = new Apple();
Orange b = new Orange();
s.push(a);
s.push(b);
a = (Apple) (s.pop());
run-time error
33
Parameterized stack
34
Generic stack: linked-list implementation
We implemented: StackOfStrings.
public class LinkedStackOfStrings
{
private Node first = null;
We also want: StackOfURLs, StackOfInts, StackOfVans, ….
private class Node
{
String item;
Node next;
}
Attempt 3. Java generics.
・Avoid casting in client.
・Discover type mismatch errors at compile-time instead of run-time.
public boolean isEmpty()
{ return first == null;
type parameter
Stack<Apple> s = new Stack<Apple>();
Apple a = new Apple();
Orange b = new Orange();
s.push(a);
s.push(b);
public class Stack<Item>
{
private Node first = null;
compile-time error
a = s.pop();
}
private class Node
{
Item item;
Node next;
}
public boolean isEmpty()
{ return first == null;
}
generic type name
}
public void push(String item)
{
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
}
public void push(Item item)
{
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
}
public String pop()
{
String item = first.item;
first = first.next;
return item;
}
public Item pop()
{
Item item = first.item;
first = first.next;
return item;
}
}
Guiding principles. Welcome compile-time errors; avoid run-time errors.
35
36
Generic stack: array implementation
Generic stack: array implementation
the way it should be
public class FixedCapacityStackOfStrings
{
private String[] s;
private int N = 0;
the way it is
public class FixedCapacityStack<Item>
{
private Item[] s;
private int N = 0;
public class FixedCapacityStackOfStrings
{
private String[] s;
private int N = 0;
public class FixedCapacityStack<Item>
{
private Item[] s;
private int N = 0;
public ..StackOfStrings(int capacity)
{ s = new String[capacity]; }
public FixedCapacityStack(int capacity)
{ s = new Item[capacity]; }
public ..StackOfStrings(int capacity)
{ s = new String[capacity]; }
public FixedCapacityStack(int capacity)
{ s = (Item[]) new Object[capacity]; }
public boolean isEmpty()
{ return N == 0; }
public boolean isEmpty()
{ return N == 0; }
public boolean isEmpty()
{ return N == 0; }
public boolean isEmpty()
{ return N == 0; }
public void push(String item)
{ s[N++] = item; }
public void push(Item item)
{ s[N++] = item; }
public void push(String item)
{ s[N++] = item; }
public void push(Item item)
{ s[N++] = item; }
public String pop()
{ return s[--N]; }
public Item pop()
{ return s[--N];
public String pop()
{ return s[--N]; }
public Item pop()
{ return s[--N];
}
}
}
}
}
}
@#$*! generic array creation not allowed in Java
the ugly cast
37
Unchecked cast
38
Generic data types: autoboxing
Q. What to do about primitive types?
Wrapper type.
% javac FixedCapacityStack.java
Note: FixedCapacityStack.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
・Each primitive type has a wrapper object type.
・Ex: Integer is wrapper type for int.
% javac -Xlint:unchecked FixedCapacityStack.java
FixedCapacityStack.java:26: warning: [unchecked] unchecked cast
found
: java.lang.Object[]
required: Item[]
a = (Item[]) new Object[capacity];
^
1 warning
Autoboxing. Automatic cast between a primitive type and its wrapper.
Stack<Integer> s = new Stack<Integer>();
s.push(17);
// s.push(Integer.valueOf(17));
int a = s.pop();
// int a = s.pop().intValue();
Bottom line. Client code can use generic stack for any type of data.
39
40
Iteration
Design challenge. Support iteration over stack items by client,
without revealing the internal representation of the stack.
i
1.3 B AGS , QUEUES, AND S TACKS
s[]
‣ stacks
‣ resizing arrays
Algorithms
R OBERT S EDGEWICK | K EVIN W AYNE
http://algs4.cs.princeton.edu
N
it
was
the
best
of
times
null
null
null
null
0
1
2
3
4
5
6
7
8
9
first
current
‣ queues
of
times
‣ generics
best
the
was
null
it
‣ iterators
‣ applications
Java solution. Make stack implement the java.lang.Iterable interface.
42
Iterators
Stack iterator: linked-list implementation
Iterable interface
Q. What is an Iterable ?
A. Has a method that returns an Iterator.
import java.util.Iterator;
public interface Iterable<Item>
{
Iterator<Item> iterator();
}
public class Stack<Item> implements Iterable<Item>
{
...
public Iterator<Item> iterator() { return new ListIterator(); }
Q. What is an Iterator ?
Iterator interface
private class ListIterator implements Iterator<Item>
{
private Node current = first;
A. Has methods hasNext() and next().
Q. Why make data structures Iterable ?
A. Java supports elegant client code.
“foreach” statement (shorthand)
for (String s : stack)
StdOut.println(s);
public interface Iterator<Item>
{
boolean hasNext();
Item next();
optional; use
void remove();
at your own risk
}
public boolean hasNext() { return current != null; }
public void remove()
{ /* not supported */
}
public Item next()
{
throw UnsupportedOperationException
Item item = current.item;
throw NoSuchElementException
if no more items in iteration
current
= current.next;
return item;
}
equivalent code (longhand)
}
Iterator<String> i = stack.iterator();
while (i.hasNext())
{
String s = i.next();
StdOut.println(s);
}
}
first
times
43
current
of
best
the
was
it
null
44
Stack iterator: array implementation
Iteration: concurrent modification
Q. What if client modifies the data structure while iterating?
import java.util.Iterator;
A. A fail-fast iterator throws a java.util.ConcurrentModificationException.
public class Stack<Item> implements Iterable<Item>
{
…
concurrent modification
for (String s : stack)
stack.push(s);
public Iterator<Item> iterator()
{ return new ReverseArrayIterator(); }
private class ReverseArrayIterator implements Iterator<Item>
{
private int i = N;
public boolean hasNext() {
public void remove()
{
public Item next()
{
return i > 0;
/* not supported */
return s[--i];
}
}
}
To detect:
・Count total number of push() and pop() operations in Stack.
・Save counts in *Iterator subclass upon creation.
・If, when calling next() and hasNext(), the current counts do not equal
}
}
i
s[]
the saved counts, throw exception.
N
it
was
the
best
of
times
null
null
null
null
0
1
2
3
4
5
6
7
8
9
45
46
Java collections library
List interface. java.util.List is API for an sequence of items.
public interface List<Item> implements Iterable<Item>
List()
1.3 B AGS, Q UEUES, AND S TACKS
boolean isEmpty()
int size()
Algorithms
R OBERT S EDGEWICK | K EVIN W AYNE
http://algs4.cs.princeton.edu
‣ stacks
void add(Item item)
‣ resizing arrays
Item get(int index)
‣ queues
Item remove(int index)
‣ generics
‣ iterators
‣ applications
boolean contains(Item item)
Iteartor<Item> iterator()
create an empty list
is the list empty?
number of items
append item to the end
return item at given index
return and delete item at given index
does the list contain the given item?
iterator over all items in the list
...
Implementations. java.util.ArrayList uses resizing array;
java.util.LinkedList uses linked list.
caveat: only some
operations are efficient
48
Java collections library
Java collections library
java.util.Stack.
java.util.Stack.
・Supports push(), pop(), and and iteration.
・Extends java.util.Vector, which implements java.util.List
・Supports push(), pop(), and and iteration.
・Extends java.util.Vector, which implements java.util.List
interface from previous slide, including get() and remove().
interface from previous slide, including get() and remove().
・Bloated and poorly-designed API (why?)
・Bloated and poorly-designed API (why?)
Java 1.3 bug report (June 27, 2001)
The iterator method on java.util.Stack iterates through a Stack from
the bottom up. One would think that it should iterate as if it were
popping off the top of the Stack.
status (closed, will not fix)
java.util.Queue. An interface, not an implementation of a queue.
It was an incorrect design decision to have Stack extend Vector ("is-a"
rather than "has-a"). We sympathize with the submitter but cannot fix
this because of compatibility.
Best practices. Use our implementations of Stack, Queue, and Bag.
49
War story (from Assignment 1)
Stack applications
Generate random open sites in an N-by-N percolation system.
・Jenny:
percolates
blocked
pick (i, j) at random; if already open, repeat.
does not percolate
site
Takes ~ c1 N 2 seconds.
・Kenny:
create a java.util.ArrayList of N 2 closed sites.
Pick an index at random and delete.
open
Takes ~ c2 N 4 seconds.
50
site
open site connected to top
no open site connected to top
・Parsing in a compiler.
・Java virtual machine.
・Undo in a word processor.
・Back button in a Web browser.
・PostScript language for printers.
・Implementing function calls in a compiler.
・...
Why is my program so slow?
Kenny
Lesson. Don't use a library until you understand its API!
This course. Can't use a library until we've implemented it in class.
51
52
it is easy to convince yourself that it computes the proper value: any time the algorithm encounters a subexpression consisting of two operands separated by an op-
Function calls
Arithmetic expressionerator,
evaluation
all surrounded by parentheses, it leaves the result of performing that operation on those operands on the operand stack. The result is the same as if that value
had appeared in the input instead of the subexpression, so we can think of replacing
valuethe
stack
Goal. Evaluate infix expressions.
(1+((2+3)*(4*5)))
subexpression by the value to get an
expression
operator
stack
that would yield the same result. We can apply
1
+((2+3)*(4*5)))
this argument again and again until we get a
( 1 + ( ( 2 + 3 ) * ( 4
* 5value.
) )For) example, the algorithm comsingle
1
((2+3)*(4*5)))
putes the same value of all of these expres+
sions:
1 2
How a compiler implements a function.
・Function call: push local environment and return address.
・Return: pop return address and local environment.
operand
Recursive function. Function that calls itself.
Note. Can always use an explicit stack to remove recursion.
operator
( 1
( 1
( 1
( 1
101
+
+
+
+
( (
( 5
( 5
100
2 + 3 ) * ( 4 * 5 ) ) )
* ( 4 * 5 ) ) )
* 20 ) )
)
Two-stack algorithm. [E. W. Dijkstra]
static int gcd(int p, int q) {
if (q == 0) return p;
else return gcd(q,gcd
p %(192,
q); 24)
}
static int gcd(int p, int q) {
p = 192, q = 24
if (q == 0) return p;
gcd
else return gcd(q, p
% (24,
q); 0)
}
static int gcd(int p, int q) {
if (q == 0) return p;
p = 24, q = 0
else return gcd(q, p % q);
}
p = 216, q = 192
53
Dijkstra's two-stack algorithm demo
value stack
1
+
(
(
2
+
operand
3
)*(4*5)))
54
Arithmetic expression evaluation
public class Evaluate
{
public static void main(String[] args)
{
Stack<String> ops = new Stack<String>();
Stack<Double> vals = new Stack<Double>();
while (!StdIn.isEmpty()) {
String s = StdIn.readString();
if
(s.equals("("))
;
else if (s.equals("+"))
ops.push(s);
else if (s.equals("*"))
ops.push(s);
else if (s.equals(")"))
{
String op = ops.pop();
if
(op.equals("+")) vals.push(vals.pop() + vals.pop());
else if (op.equals("*")) vals.push(vals.pop() * vals.pop());
}
else vals.push(Double.parseDouble(s));
}
StdOut.println(vals.pop());
}
% java Evaluate
}
( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
101.0
operator stack
(fully parenthesized)
(
3)*(4*5)))
1 2 3
+ +
(PROGRAM 4.3.5) is an implemen1 5
Value: push onto the
stack.This code is a simple
tationvalue
of this method.
*(4*5)))
+
example of an interpreter : a program that in1 5
Operator: push onto
the
operator
stack.
terprets the computation specified by a given
(4*5)))
+ *
string and performs the computation to ar1 5 4
Left parenthesis: ignore.
rive at the result. A compiler is a program that
*5)))
+ *
the string into code on a lower-level
Right parenthesis: converts
pop
operator
and
two
values;
1 5 4
machine that can do the job. This conversion
5)))
+ * *
is a more complicated
process than the steppush the result of applying
that operator
1 5 4 5
by-step conversion used by an interpreter, but
)))
+ * *
it is based
the same underlying
to those values onto
the on
operand
stack.mechanism.
1 5 20
Initially, Java was based on using an interpret))
+ *
er. Now, however, the Java system includes a
1 100
compiler that converts arithmetic expressions
)
+
(and, more generally, Java programs) into code
101
for the Java virtual machine, an imaginary maContext. An interpreter!
chine that is easy to simulate on an actual computer.
Trace of expression evaluation (Program 4.3.5)
introJava.indb 573
infix expression
+3)*(4*5)))
Evaluate
・
・
・
・
gcd (216, 192)
+
1 2
+ +
)
*
(
4
*
5
)
)
)
1/3/08 4:16:56
operator
55
56
Correctness
Stack-based programming languages
Q. Why correct?
Observation 1. Dijkstra's two-stack algorithm computes the same value if
A. When algorithm encounters an operator surrounded by two values
the operator occurs after the two values.
within parentheses, it leaves the result on the value stack.
( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + )
as if the original input were:
Observation 2. All of the parentheses are redundant!
( 1 + ( 5 * ( 4 * 5 ) ) )
1 2 3 + 4 5 * * +
Jan Lukasiewicz
Repeating the argument:
( 1 + ( 5 * 20 ) )
( 1 + 100 )
101
Bottom line. Postfix or "reverse Polish" notation.
Extensions. More ops, precedence order, associativity.
Applications. Postscript, Forth, calculators, Java virtual machine, …
57
58