Professional Documents
Culture Documents
Objectives
• Introduction • Implementations
– Define a stack • Array-based
– Define a queue implementations
• Operations • Applications
– Stack operations – Stack applications
– Queue operations – Queue applications
• Java interfaces
– PureStack interface
– PureQueue interface
What is a stack?
• A stack is a finite sequence of elements in which
the only element that can be removed is the
element that was most recently inserted.
top
B
top top
A A A
top
Stack Operations
Assume a simple stack for integers.
Stack s = new Stack();
s.push(12);
s.push(4);
s.push( s.top() + 2 );
s.pop()
s.push( s.top() );
//what are contents of stack?
6
Stack Operations :
/**
* Inserts a specified element on the top of this
* PureStack object.
*
* @param element – the element to be pushed.
*
*/
void push (E element);
/**
* Removes the top element from this PureStack object.
*
* @return – the element removed.
* @throws NoSuchElementException – if this PureStack
* object is empty.
*/
E pop();
/**
* Returns the top element on this PureStack object.
*
* @return – the element returned.
* @throws NoSuchElementException – if this PureStack
* object is empty.
*/
E peek();
} // interface PureStack
Generic Types
What is this <E> in the interface definition?
• It represents a generic type
– For generality, we can define a class ( for interface) based
on a generic type rather than as actual type
– Example: a Stack for object of type E
• The actual type is known only when an application
program creates an object of that class
• We can then create stacks of different types:
– stack<int> stackOfIntegers = new Stack<int>();
– stack<String> stackOfString = new Stack<String>();
Implementing an Interface
One or more classes can implement an
interface, perhaps differently
• A class implements the interface by providing
the implementations (bodies) for each of the
abstract methods
• Uses the reserved word implements followed
by interface name
Stack implementation issues
• What do we need to implement a stack?
s stack
4
top
s stack
5
top
Array Implementation of a Stack
After popping one element
0 1 2 3 4 5 6
……..
s stack
4
top
s stack
3
top
The ArrayPureStack Class
• The class ArrayPureStack implements the PureStack
interface:
Public class ArrayPureStack <E> implements PureStack <E>
? ? ? ? ?
s stack 0 1 2 3 4
size
Example: the same ArrayPureStack object after
four items have been pushed on
s.push(41);
s.push(56);
s.push(32); 41 56 32 17 ?
s.push(17); s stack 0 1 2 3 4
4
size
Example: the same ArrayPureStack object after
two items have been pop out
s.pop();
s.pop();
41 56 ? ? ?
s stack 0 1 2 3 4
2
size
The ArrayPureStack Class
The push() operation
• Adds the specified element to the top of the stack,
expanding the capacity of the stack array if necessary
public void push(E element)
{ if (size == stack.length)
expandCapacity();
stack[size++]=element;
}
Managing Capacity
• An array has a particular number of cell when it is
created (its capacity), so array’s capacity is also
the stack’s capacity
• What happens when we want to push a bew
element onto a stack that is full?
– The push method could throw an exception
– It could return status indicator (i.e. a boolean value
true or false, that indicates whether the push was
successful or not)
– It could automatically expand the capacity of the array.
The ArrayPureStack Class
The expandCapacity() operation
• To create a new array to store the contents of the
stack, with twice the capacity
public void expandCapacity()
{ E[] larger = (E[]) new Object[stack.length * 2];
System.arraycopy(stack,0,larger,0,size);
stack = larger;
}
The ArrayPureStack Class
The pop() operation
• Removes the element at the top of the stack and
returns a reference to it.
public E pop()
{
return data[--size];
}
The ArrayPureStack Class
The size() operation
• Returns the number of elements in the stack
public int size()
{
return size;
}
The ArrayPureStack Class
The peek() operation
• Returns a reference to the element at the top of the
stack, the element is not removed from the stack
public E peek()
{
return data[size-1];
}
Stack Applications
Stack Applications
Used of stack in computing
• Word Processors , editors
– To check expressions or string of text for matching
parentheses / brackets
• i.e. if (a==b)
{ c=(d+e) * f; }
– To implement undo operations
• Keeps track of the most recent operations
Stack Applications cont…
Used of stack in computing
• Stack Calculators
– To convert an infix expression to postfix, to make
evaluation easier
• i.e. Infix expression: a*b+c
postfix expression: ab*c+
– To evaluate postfix expression
Stack Applications cont…
Used of stack in computing
• Call stacks (Runtime stack)
– Used by runtime system when methods are
invoked, for method call/return processing
• i.e. main method, calls method1
method1 call method2
method2 returns …
– Hold “call frame” which containing local variables,
parameters, etc…
Stack Applications cont…
Used of stack in computing
• Compilers
– To convert infix expressions to postfix, to make
translation of a high-level language such as Java or
C to a lower level language easier
– Focus more on this
Compilers
• Old compilers:
Infix Machine language
– This gets messy because of parentheses.
• Newer compilers:
Infix Postfix Machine language
Infix and Postfix notation
• In infix notation, an operator is placed between its operands.
• In postfix notation, an operator is placed immediately after
its operands. Parentheses are not needed and not used, in
postfix.
Infix Postfix
a+b ab+
a+b*c abc*+
a*b+c ab*c+
(a + b) * c ab+c*
Infix to Postfix Conversion
The idea of converting infix to postfix using a stack:
Example. Convert infix a + b * c to postfix abc*+.
We scan the input stream left to right, output each operand as they are
scanned. The main idea is that when encountering an operator, it is pushed
onto the stack if the stack is empty, or if it has a higher precedence than that
of the stack top. Thus, the following chart demonstrates the snapshots of the
input stream vs. the stack and the output during the conversion process:
next token stack output comments
(Initially) empty none a empty a
always output operand + + a push when stack
empty b + ab always output operand * +
* ab push if higher precedence c + * a b c
always output operand (at end) empty a b c * + pop
everything off stack
Infix to Postfix Conversion cont…
Another example: Convert infix a*(b + c)/d to postfix abc+*d/.
next token stack output comments
(Initially) empty none a empty a
output operand * * a push operator if stack
empty ( *( a always push ( b *( ab
output operand + *(+ ab push operator if stack
top ( c *(+ abc output operand ) * abc+
pop all operators until ( / / abc+* pop *,
push / d / abc+*d output operand (at
end) empty abc+*d/ pop everything off stack
Note that the token ( is pushed onto stack when scanned; once it is in the
stack all operators are considered with a higher precedence against (. Also,
we need to resolve operators with left or right-associative properties. For
example, a+b+c means (a+b)+c but a^b^c means a^(b^c).
Infix to Postfix Conversion cont…
We define the precedence levels of various operators including the
parentheses, distinguishing whether the operators are currently inside the
stack or they are incoming tokens.
operator tokens in-stack precedence in-coming precedence
(ISP) (ICP) ) (N/A)
(N/A) ^ 3 4 *, / 2
2 +, – 1 1
( 0 4 $ –1
(N/A)
The idea is that when encountering an in-coming operator, pop all operators
in the stack that have a higher or equal ISP than the ICP of the new operator,
then push the new operator onto the stack. The initial stack is marked with a
“bottom marker” $ with a –1 precedence, which serves as a control symbol.
Infix to Postfix Conversion cont…
Rules for converting the infix string:
Starting from the left hand end, inspect each character of the string
1. if it’s an operand – append it to the postfix string
2. if it’s a ‘(‘ – push it on the stack
3. if it’s an operator – if the stack is empty, push it on the stack else pop operators of
greater or equal precedence and append them to the postfix string, stopping when
a ‘(‘ is reached, an operator of lower precedence is reached, or the stack is empty;
then push the operator on the stack
4. if it’s a ‘)’ – pop operators off the stack, appending them to the postfix string, until
a ‘(‘ is encountered and pop the ‘(‘ off the stack
5. when the end of the infix string is reached – pop any remaining operators off the
stack and append them to the postfix string
Infix to Postfix Conversion (continued)
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
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
Algorithm for Balanced Symbol Checking
• Make an empty stack
• read symbols until end of file
– if the symbol is an opening symbol push it onto the
stack
– if it is a closing symbol do the following
• if the stack is empty report an error
• otherwise pop the stack. If the symbol popped does not
match the closing symbol report an error
• At the end of the file if the stack is not empty
report an error
Example
[
(
{
{
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
) } }
{
( 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 brakets
{
{ Still need to process
} }
Pop last two. They match.
All is okay
– The two remaining closing curly brakets 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 '}'.
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.
Evaluating postfix expressions
4
s.push(3); 3
s.push(4);
right = s.pop(); // found operator - so pop
left = s.pop();
s.push(left - right); -1
3 - 4
– The stack now has one value -1
– The remainder of the expression: 5 3 * -
Continue with 5 3 * -
Found operand so push
Found operand so push
Found operator so pop two values,
apply operand, and push the result
3
s.push(5); 5
s.push(3);
-1
right = s.pop();
left = s.pop();
s.push(left * right); 15
5 * 3 -1
– The Stack has 2 values
– Only one token remains
Continue with -
15
-1
61
Queue Operations
1. Enqueue : Add an element to the tail of the queue
2. Dequeue : Remove the element at the head of the queue
3. Peek : Look at but do not remove the element at the head
of the queue
Note: These are the standard queue operations. Java 1.5 has a queue
interface which has operations with different names.
Enqueue and Dequeue
• Primary queue operations: Enqueue and Dequeue
• Like check-out lines in a store, a queue has a front and
a back.
• Enqueue
– Insert an element at the back of the queue
• Dequeue
– Remove an element from the front of the queue
Remove Insert
(Dequeue) front rear (Enqueue)
Enqueue and Dequeue
Enqueue “Matt” Enqueue “Andrew” Enqueue “Samira”
Dequeue
Andrew Samira
Front Back
The PureQueue interface
public interface PureQueue<E>
{
// Returns the number of elements in this PureQueue
// object.
int size( );
/**
* Removes the front element from this PureQueue
* object.
*
* @return – the element removed.
* @throws NoSuchElementException – if this
* PureQueue object is empty.
*/
E dequeue();
/**
* Returns the front element in this PureQueue
* object.
*
* @return – the element returned.
*
* @throws NoSuchElementException – if
* PureQueue object is empty.
*
*/
E front();
} // interface PureQueue
Queue Example
Operation Output Q
enqueue(5) – (5)
enqueue(3) – (5, 3)
dequeue() 5 (3)
enqueue(7) – (3, 7)
dequeue() 3 (7)
front() 7 (7)
dequeue() 7 ()
dequeue() “error” ()
isEmpty() true ()
enqueue(9) – (9)
enqueue(7) – (9, 7)
size() 2 (9, 7)
enqueue(3) – (9, 7, 3)
enqueue(5) – (9, 7, 3, 5)
dequeue() 9 (7, 3, 5)
69
Implementation of Queue
There are many ways to implement a queue:
1. Array
2. Circular queue
3. Linked List
Array implementation of queues cont…
• There are several different algorithms to
implement Enqueue and Dequeue
• Naïve way
– When enqueuing, the front index is always fixed
back
and the back index moves forward in the array.
back
back
3 3 6 3 6 9
6 9 9
• Better way
– When an item is enqueued, make the back index
move forward.
0 1 2 3 4 5 6 7
myQueue:
17 23 97 44
front = 0 back = 3
Initial queue: 17 23 97 44
front = 1 back = 4
• Notice how the array contents “crawl” to the right as elements are inserted and
deleted
• This will be a problem after a while!
Circular arrays
• We can treat the array holding the queue elements as
circular (joined at the ends)
0 1 2 3 4 5 6 7
myQueue:
44 55 11 22 33
back = 1 front = 5
rear = 4 front = 5
rear = 4 front = 5
This is a problem! (same) –How to determine it is full or empty
Full and empty queues: solutions
• Solution #1: Keep an additional variable
0 1 2 3 4 5 6 7
myQueue:
44 55 66 77 88 11 22 33
0 1 2 3 4 5 6 7
myQueue:
44 55 66 77 11 22 33
rear = 3 front = 5
Applications of Queues
• Operating systems use queues to sequence tasks
waiting for a scarce resource
– Printer queue
– Tasks waiting for CPU