2. 7-2 Stacks
A Stack
Is a collection with one accessible element--the
most recent element "pushed" onto the stack.
Has a Last-In, First-Out (LIFO) characteristic
Used often in computer systems
• maintain order of method calls (demo stack of calls)
• compiler matches openers { [ ( and closers ) } ]
• converting expressions into postfix notation
Useful in applications where a last-in-first-out
characteristic makes sense to the programmer
3. 7-3 Using a Stack Object
// Construct an empty stack using Interface in book
GenericStack stackOfInts = new ArrayStack( );
// Push three string values onto the stack
stackOfInts.push( new Integer( 1 ) );
stackOfInts.push( new Integer( 2 ) );
stackOfInts.push( new Integer( 3 ) );
// Show each element before removed in a LIFO order
while( !stackOfInts.isEmpty( ) )
{ // Print the value as it is removed from top of stack
System.out.println( stackOfInts.pop( ) );
}
4. 7-4 You push references to objects
A reference to an Object object is pushed
yes, anObject is an Object object
public void push( Object anObject )
{
...
}
You can not s.push(12) or s.push('A')
However you can push a reference to any
Java object including your objects
5. 7-5 Type Conversion
You will have to convert references from Object
to its proper class. The following works if
stackOfInts contains only Integer objects
System.out.println(
((Integer)stackOfInts.getTop()).intValue () );
Cast Object to a Integer by preceding it with
Integer within parentheses
(Integer)s.getTop()
But you need an extra set of parentheses before sending
a length message
( (Integer)s.getTop() ).intValue()
6. 7-6
Cast from Object to
BankAccount Stack of BankAccounts is silly
GenericStack s = new ArrayStack( );
s.push( new BankAccount( "Barb", 100.00 ) );
s.push( new BankAccount( "Huey", 200.00 ) );
s.push( new BankAccount( "Zeke", 300.00 ) );
while( ! s.isEmpty() )
{ // The . is highest priority, then ( )
BankAccount ref = (BankAccount)s.pop();
// Had to cast just to trick the compiler
double balance = ref.getBalance( );
String ID = ref.getID( );
System.out.println( ID + " has $" + balance );
}
Output
Zeke has $300.0
Huey has $200.0
Barb has $100.0
7. 7-7 Stacks (continued)
Stack methods names:
push elements onto the "top" of a stack.
pop elements off the "top" of the stack
isEmpty true is there are no elements
getTop provides access only the top element
• the most recently pushed element
Some methods throw EmptyStackException
pop and getTop
8. 7-8 Construct, push, top, pop
The memory shown to the right after
executing the code on the left:
ArrayStack s = new ArrayStack();
s.push("A"); // strings ok, chars not
s.push("B");
s.push("C");
What is the value of s.getTop() now?
Here's what happens with: s.pop();
"B"
"C"
"A"
"B"
"A"
9. 7-9
Applications of Stacks:
With Computer Languages
Imagine a compiler scanning code when you
forget ) or ] or }
It's difficult to find the source of the error
compilers check to see if things aren't balanced
Push opening symbols onto a stack and see if
closing symbols make sense
compile a Java with several errors
Algorithm follows
10. 7-10 Balancing Symbols
openers [ ( { and closers ] ) }
public class A
public static void main(String[ args
System.out PRINTln( "Hello" );
for( int j = 0; j < 6 j++ ) j++
doub x = 0.0;
inTeger j = 0;
System.out.println( "Goodbye" );
}
}
Java says 2 errors, but how many can you find?
A.java:1: '{' expected.
A.java:12: Unbalanced parentheses
2 errors
11. 7-11 Checks Balanced Symbols First
Java's compiler apparently first checks to see
if certain symbols are balanced [] {} ()
It ignores others errors by making a run over
the entire source code just looking for
unbalanced symbols
If it finds none, it will begin a new pass
starts reading character by character again
Fix the unbalanced errors of the previous
slide one by one to observe this behavior
it probably uses a Stack and an algorithm like this
12. 7-12
Example 1: Reporting errors
on unclosed symbols
1. Make an empty stack named s
2. Read symbols until end of file
if it's an opening symbol, push it
if it is a closing symbol && s.isEmpty
report error
otherwise
pop the stack
if symbol is not a closer for pop's value, report error
3. At end of file, if !s.isEmpty, report error
Use Java code with mismatched symbols as input
13. 7-13 Example
Process these characters, which represent
only the openers and closers in a short Java
program: {{([])}}
As the first four characters are read — all
openers —push each onto the stack
[
(
{
{
14. 7-14
Pop the first closer
Do they match?
The next symbol read is a closer: ']'.
Pop '[' and compare to ']'.
Since they match, no error would be reported.
The stack would now look like this:
(
{
{
Still need to process
) } }
15. 7-15 ( matches )
Then ' )' is found, so pop the stack
Since the top symbol '(' matches the closer ')',
no error needs to be reported.
The stack now has two opening curly braces
{
{ Still need to process
} }
16. 7-16
Pop last two. They match.
All is okay
The two remaining closing curly braces
would cause the two matching openers to be
popped with no errors
It is the last in first out nature of stacks that
allows the first '{' to be associated with the
last closer '}'.
17. 7-17 When do errors occur?
♦If a closer is found and the stack is empty,
you could also report an error.
− For example with}}, where the opening { was not
incorrectly typed, the stack has no openers.
♦If you process all symbols and the stack is
not empty, an error should be reported,
− In the case of {{([])} there is a missing right
curly brace. Symbols are processed without error.
− Except at the end, the stack should be empty. It is
not and an error gets reported.
18. 7-18 Implementing a Stack
Let us implement our own stack class to store
a stack of primitive characters
Methods will include
push
pop
getTop
isEmpty
19. 7-19 Implementing a stack
There are a variety of ways
Don't implement it and simply use Java's Stack class
Use an array instance variable will do this now
Use a linked structure this will be the quiz
Or just use LinkedList (getFront and removeFront)
First consider an array based implementation
21. 7-21
Implement a Stack with an
array instance variable
The class has been defined, fill in the blanks
public class ArrayStack
{ // Instance Variables
private Object[] my_data;
private int my_top;
/** Construct empty stack with capacity 10 */
public ArrayStack( )
{ // YOU COMPLETE THIS
}
22. 7-22 ArrayStack.push
/** Put element on "top" of this Stack object.
* @param element The Object that will be
* placed at the top of this stack object */
public void push( Object element )
{ // YOU COMPLETE THIS
}
23. 7-23 ArrayStack.isEmpty
/** Determine if this stack object has more
* than 0 elements.
* @return true if there is at least one
* element in this stack object
*/
public boolean isEmpty( )
{ // YOU COMPLETE THIS
}
24. 7-24 ArrayStack getTop
this is complete
This method check for an empty stack
assume import java.util.EmptyStackException
/** @return reference to the element at the
* top of this stack object
*/
public Object getTop()
{ // Throw exception if this stack is empty
if( this.isEmpty() )
throw new EmptyStackException( );
// Program may have terminated already
return my_data[my_top];
}
25. 7-25 ArrayStack now has Exceptions
Now, if you try to reference the top of an empty
stack like this
while( !( s.isEmpty() ) )
s.pop( );
// s is now definitely empty
System.out.println( s.getTop( ) ); // Exception
you will get something like this:
Exception in thread "main"
java.util.EmptyStackException
at ArrayStack.getTop(ArrayStack.java:31)
at ArrayStack.main(Compiled Code)
26. 7-26 ArrayStack pop
/** Remove the element from top of this stack
* while returning a reference to the object
* at the top of stack */
public Object pop( ) throws EmptyStackException
{ // YOU COMPLETE THIS
}
27. 7-27
Example 3:
Evaluating postfix expressions
Stacks set up the evaluation of expressions.
4 + 8 / 2 is different if evaluated left to right.
Evaluating "infix" expressions is not easy.
So compilers convert what we write in infix into the
equivalent postfix expression.
The expression 2 plus 2 in postfix 2 2 +
Postfix of 1-2+3*3/4 is
1 2 - 3 3 * 4 / +
28. 7-28 Evaluating Postfix Expression
How do we evaluate these expressions?
Steps for evaluating postfix expressions
Evaluate from left to right
At each occurrence of an operator, apply it to the
two operands to the left and replace these three
items with the single value.
// Use this stack to help on the next slides
GenericStack s = new ArrayStack( );
29. 7-29 Evaluate 3 4 - 5 3 * -
s.push( 3 );
s.push( 4 );
op2 = s.pop( ); // found operator - so pop
op1 = s.pop( );
s.push( op1 - op2 );
3 - 4
The stack now has one value -1
The remainder of the expression: 5 3 * -
-1
3
4
Found operand so push
Found operand so push
Found operator so pop two values,
apply operand, and push the result
30. 7-30 Continue with 5 3 * -
s.push( 5 );
s.push( 3 );
op2 = s.pop();
op1 = s.pop();
s.push( op1*op2 );
5 * 3
The Stack has 2 values
Only one token remains
15
5
3
-1
Found operand so push
Found operand so push
Found operator so pop two values,
apply operand, and push the result
-1
31. 7-31 Continue with -
op2 = s.pop(); // found operator -
op1 = s.pop ();
s.push( op1-op2 );
-1 - 15
The expression has been processed.
The value at the top of the stack is the value of
the expression is -16
Now evaluate 2 3 4 * 5 * -
15
-1
-16
32. 7-32 Converting Infix to Postfix
1 + 2 * 3 ^ 4 in postfix 1 2 3 4 ^ * +
Note: ^ is a symbol in some languages for exponentiation
Operators are in reverse order
So we need to store them on a stack
When an operand is encountered, pop higher order
operands before pushing the lower order operand
Algorithm on the next slide
33. 7-33
Part of an algorithm for
creating a postfix "String"
Let postfix be a String that is "" and stack be an empty Stack
For each token in the input stream {
if operand: Immediately concatenate operand to postfix
if open parentheses: Push '(' on the stack
if close parentheses: Pop stack symbols and attach to
postfix until open parentheses is at getTop, then pop ')'
if operator: While the stack is not empty, pop all operators
as long as they are of equal or higher precedence and the
top is not '('. Concatenate each operator from stack to
postfix. Then push the current operator.
}
Pop any remaining operators from the stack, concatenating them
to the postfix expression
Note: Left parentheses are treated as a high precedence operator on input but
as a low precedence operator when on the stack
34. 7-34
Queues: Containers with First
in first out access
A Queue is another name for waiting line
Ex: Submit jobs to a network printer
What gets printed first?
• The most recently submitted print job?
– No! that would be a stack characteristic
• Print the least recently submitted no priorities given
• Add new print jobs at the end of the queue
Queue have First In First Out (FIFO) access
to elements could we also say Last In Last Out (LILO)?
35. 7-35 Is there a Java Queue class?
Some languages have a queue class or Queue is part
of a library that works with the language
Java does not it uses class LinkedList to offer the functionality
Outline of what we'll do
design an interface for Queue
review the Java interface again
show why array based version is difficult
show an implementation with Java's LinkedList class
implement the interface using a linked structure with
two external references: front and back
36. 7-36 Designing a Queue Interface
Queues typically provide these operations
enqueue adds an element at the end of the queue
getFront returns a reference to the element at the front of the
queue
dequeue removes the element from the front of the queue and
returns a reference to the front element
isEmpty returns false if there is at least one element in the
queue
So we will accept these methods as a well-
understood interface for queue
37. 7-37 Specify the interface
Already been done for us. It is well understood.
This will be an example of using an interface and
alternative implementations
Something collection libraries do to allow tradeoffs between
program speed and memory usage
First, design the interface
capture methods with return types, parameters
The Queue interface declares that users can enqueue and
dequeue any Object object or anything that extends
Object which is everything except primitive values
38. 7-38 The Queue Interface
public interface Queue
{
// Add any object at the end this queue
public void enqueue( Object newEl );
// Returns a reference to the object at the
// front of this Q (you will need to cast)
public Object getFront( );
// Remove the object from the front of this Q
public Object dequeue( );
// Return true if this Q is empty
public boolean isEmpty( );
}
39. 7-39
Java interfaces specify the
methods a class must have
A Java interface is the ultimate abstract class
method headings, no implementation
An interface has these things only
public method headings with ; rather than {/*...*/}
public static final data fields occasionally
A class is said to implement an interface if the
class implements all methods with headings as-is
public class AbtractList implements List
Interfaces don't provide any implementation no {}
40. 7-40 Specifying an interface
An interface looks like a class
Write interface instead of class
There is no implementation no { }
interfaces provides interesting capabilities
When a class implements an interface, it promises to
implement the methods (or it is a compiletime error)
Later on, we will see that the Comparable interface
comes in very handy for generic collections
• It guarantees a class has the compareTo method
41. 7-41
Let SlowQueue implement the
Queue interface
We need to store an array of Object objects
avoids having queue of int and people and cars, and...
public class SlowQueue implements Queue
{
private int back;
private Object[] my_data;
// ...
We must now implement all methods of the Queue
interface as they are written
plus a constructor with the proper name
42. 7-42 Bad array type queue
Queue as an array could have
the front of the queue is always in my_data [0]
public SlowQueue( int max )
{
my_data = new Object[max];
back = -1;
}
back == -1
null
my_data[0] my_data[1] my_data[2] my_data[3]my_data[0] my_data[1] my_data[2] my_data[3]
nullnull null
So far so good. An empty queue
43. 7-43 First version of enqueue
public void enqueue( Object element )
{ // This method will be changed later
back++;
my_data[back] = element;
}
Send an enqueue message
aQueue.enqueue( "a" );
So far so good. A queue of size 1
null
my_data[0] my_data[1] my_data[2] my_data[3]my_data[0] my_data[1] my_data[2] my_data[3]
null"a""a" null
back == 0
44. 7-44 enqueue another
public void enqueue( Object element )
{ // This method will be changed later
back++;
my_data[back] = element;
}
Send two more enqueue messages
aQueue.enqueue( "b" );
aQueue.enqueue( "c" );
So far so good. A Queue of size 3
"c""c"
my_data[0] my_data[1] my_data[2] my_data[3]my_data[0] my_data[1] my_data[2] my_data[3]
"b""b""a""a" null
back == 2
45. 7-45
Array Implementation of a
Queue
During dequeue, slide all elements to the left
when if size were 999, 998 assignments necessary
"a" "b" "c"
back
"b" "c" "c"
back
Before dequeue
After dequeue
A bad algorithm for enqueue.
null
null
46. 7-46
Effect of queue operation on an
array with a "floating" front
enqueue("a")
enqueue("b")
enqueue("c")
dequeue()
enqueue("d")
dequeue()
"a" "b" "c" ?
front back
"a" "b" "c" ?
front back
"a" "b" "c" "d"
front back
"a" "b" "c" "d"
front back
47. 7-47
"e"
But what happens next when
back equals array.length?
enqueue("e") "a" "b" "c" "d"
front back
back is at the last array index
But this queue is not full
Where do you place "e"?
my_data[0] is available
Write code that increments back correctly even if back is
referencing the last available array index
? ________________________________ ?
48. 7-48 The Circular Queue
"c"
"d"
back
front
A "circular queue" implementation uses
wraparound The queue has "c" "d" "e"
either increase back by 1
or set back to 0
"a"
"b"
"e" my_data[0]my_data[0]
enqueue("e")
now works in this
"circular" queue.
It reuses previously
used array indexes
Write the code
that does this
49. 7-49
Implementing a Circular Queue
Still have to work with arrays, not circles
In order for the first and last indices to work in a
circular manner:
• increase by one element at a time
• after largest index in the array, go to zero.
back = 0 1 2 3 0 1 2 3 0 1 2 3 0 ...
could contain code you just wrote on previous slide
But what is an empty queue?
What values should be given to front and back when
the queue is constructed?
50. 7-50 Problem: A full queue can not be
distinguished from an empty queue
back front
empty
back front
1 in q
a
back
front
3 in q
a
bc
front
full q
a
bc
d
back
What does back == front imply? An empty queue, or a full queue?
One option is to have the constructor place back one slot before
front then increment back during enqueue before storing
the reference to the new element into the my_data
51. 7-51 Corrected Circular Queue
Use this trick to distinguish between full and
empty queues
The element pointed to by front never indexes the front
element— the “real” front is located at
nextIndex( front )
private int nextIndex( int index )
{ // Return an int to indicate next position
return (index + 1) % my_data.length;
}
For example, use this during getFront()
return my_data[nextIndex(front)];
52. 7-52
Correct Circular Queue
Implementation Illustrated
front
back
empty
backfront
1 in q
"a"
back
front
2 in q
"a"
"b"
back
full q
"a"
"b""c"
front
The front index is always 1 behind the actual front
Must waste one array element no big deal
53. 7-53
Correct Circular dequeue
Implementation Illustrated
back
empty q
front
back
full q
"a"
"b""c"
front
back
2 in q
"b""c"
front
back
1 in q
"c"
front
dequeue three times to make this queue empty
Demo QueueEfficency.java
54. 7-54
Quiz: Implement a Queue class
with a LinkedList instance variable
import java.util.*; // For class LinkedList
public class LinkedListQueue implements Queue
{
private LinkedList my_data;
public LinkedQueue( )
{ // 1.
}
public void enqueue( Object element )
{ // 2.
}
55. 7-55 Implement getFront & isEmpty
public Object getFront()
{ // 3. Assume queue is not empty
}
public boolean isEmpty( )
{ // 4.
}
// 5. Completely implement dequeue
56. 7-56 LinkedQueue
Show pictures of two choices
1) Maintain a front and back
• Use a dummy first node, show this in class
2) Maintain front only
• But then to enqueue, you have to traverse the entire linked
structure
In class
Write and test class LinkedQueue that implements the Queue
interface.
• Use two external references: front and back