Vous êtes sur la page 1sur 85

STACK and QUEUE

Objectives
Introduction
Define a stack
Define a queue
Operations
Stack operations
Queue operations
Java interfaces
PureStack
interface
PureQueue
interface

Implementations
Array-based
implementation
s
Applications
Stack
applications
Queue
applications

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.
A stack is a data structure that keeps objects in
Last-In-First-Out (LIFO) order
Objects are added to the top of the stack
Only the top of the stack can be accessed

Visualize this like a stack of paper (or plates)

Operations on a Stack
Operation

Description

push

Adds an element to the top of the stack

pop

Removes an element from the top of the


stack

peek

Examines the element at the top of the


stack

isEmpty

Determines whether the stack is emkpty

size

Determines the number of elements in the


stack

It is not legal to access any element other


than the one that is the top of the stack!

Push and Pop


Primary operations: Push and Pop
Push
Add an element to the top of the stack

Pop
Remove the element at the top of the
stack push an element push another
empty stack
pop
top
top
top

B
A

top

Stack Operations
1) push add data onto the stack
2) Algorithm :
- Increase top by 1
- Add new item into top location

Stack Operations
1) pop remove data onto the stack
2) Algorithm :
- Store the top data into a
temporary storage
- Decrease top by one

Stack Operations
1) stackEmpty check whether the
stack is empty or not
2) Algorithm :
- Is top = -1 ?
true

(stack is empty!)

If yes, return

Stack Operations
1) stackFull check whether the stack
is full or not
2) Algorithm :
- Is top = stackSize -1 ? If yes,
return true

(stack is full!)

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?

10

Stack Operations :
push operation
j avaxc

cxav a j
OUTPUT
c
x
a
v
a
j

Print out contents


stack in reverse
pop of
operation
order.

Exercise
Show the output and the contents of stacks S and T(using
diagrams)after each of the following sequence operations:
a. push(S,2);
b. push(S,5);
c. push(T,3);
d. push(T,4);
e. pop(topItem,S);
f. System.out.println(topItem);
g. getTop(topItem,T);
h. System.out.println (topItem);
i. push(S,topItem);
j. push(S,5);
k. pop(topItem,T);
l. System.out.println (topItem);
m. push(T,7);

Lab Exercise
Problem :
Convert a decimal value to a binary form.
Instruction:
Write a main() to accept a decimal value
from the user. Convert the decimal value
to its binary form. During the conversion,
call the push() to push the binary value 1
or 0 on to the stack. Lastly call pop()
repeatedly to pop the data out from the
stack and display.

Interface
A list of abstract methods and constants
must be public
constants must be declared as final static

Abstract method is a method that does not


have an implementation, i.e. it just consists
of the header of the method:
return type method name (parameter list)

The PureStack
Interface

/**
* 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?
A data structure (container) to hold
the data elements
Something to indicate the top of
the stack

Implementation of Stacks
Any list implementation could be
used to implement a stack
Arrays (static: the size of stack is given
initially)
Linked lists (dynamic: never become
full)

We will explore implementation


based on array

Array Implementation of a
Stack
The container will be an array to hold the
data elements
Data elements are kept contiguously at one end
of the array

The top of the stack will be indicated by its


position in the array (index)
Lets assume that the bottom of the stack is at
index 0
The top of the stack will be represented by an
integer variable that is the index on the next
available slot in the array

Array Implementation of a
Stack
A stack s with 4 elements
0

..
s

stack

4
top

After pushing an element


0

6
..

stack

5
top

Array Implementation of a
Stack

After popping one element


0

6
..

stack

4
top

After popping a second element


0

6
..

stack

3
top

The ArrayPureStack Class


The class ArrayPureStack implements the
PureStack interface:
Public class ArrayPureStack <E> implements
PureStack <E>

Attributes (instance variables):


private E[] stack;
data
private int size;
open slot

//the container for the


// indicates the next

The ArrayPureStack Class


The array variable stack holds reference to
objects
Their type is determined when the stack is
instantiated

The integer variable size represents the


index of the next available slot in the array
Example:
initially size = 0, the first element is store at index 0
after the insertion, the size = 1, so the second
element is stored at index 1.

The ArrayPureStack Class


ArrayPureStack Constructors:
Create an empty stack using default capacity
public ArrayPureStack()
{ stack = (E[]) new
Object[DEFAULT_CAPACITY];
size = 0; }
Create an empty stack using the specified
capacity
public ArrayPureStack()
{ stack = (E[]) new
Object[initial_CAPACITY];
size = 0;}

Example of using Constructor to


create a Stack of numbers
ArrayPureStack<Integer> s = new
ArrayPureStack<Integer>(5);

stack

size

Example: the same ArrayPureStack object


after four items have been pushed on

s.push(41);
s.push(56);
s.push(32);
s.push(17);

stack

4
size

41 56

32 17

Example: the same ArrayPureStack


object after two items have been pop out

s.pop();
s.pop();
s

stack

2
size

41 56

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 arrays
capacity is also the stacks capacity
What happens when we want to push a
new 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
language

Machine

This gets messy because of


parentheses.
Newer compilers:
Infix
Postfix
language

Machine

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
next
token
output
comments
stream
vs.stack
the stack
and the output
during the conversion
process: empty none
(Initially)
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


for converting the cont
infix string:

ng from the left hand end, inspect each character of t


1. if its an operand append it to the postfix string
2. if its a ( push it on the stack

if its an operator if the stack is empty, push it on the stack else pop operato
greater or equal precedence and append them to the postfix string, stopping w
a ( is reached, an operator of lower precedence is reached, or the stack is em
then push the operator on the stack

. if its a ) pop operators off the stack, appending them to the postfix string,
a ( is encountered and pop the ( off the stack

. when the end of the infix string is reached pop any remaining operators off
stack and append them to the postfix string

Infix to Postfix Conversion (continued)

ample: 7-(2*3+5)*(8-4/2) 723*5+842/-*-

maining Infix String


7-(2*3+5)*(8-4/2)
-(2*3+5)*(8-4/2)
(2*3+5)*(8-4/2)
2*3+5)*(8-4/2)
*3+5)*(8-4/2)
3+5)*(8-4/2)
+5)*(8-4/2)
5)*(8-4/2)
)*(8-4/2)
*(8-4/2)
(8-4/2)
8-4/2)
-4/2)
4/2)
/2)
2)
)
null

char Stack
empty
empty
-(
-(
-(*
-(*
-(+
-(+
-*
-*(
-*(
-*(-*(-*(-/
-*(-/
empty

Postfix String
null
7
7
7
72
72
723
723*
723*5
723*5+
723*5+
723*5+
723*5+8
723*5+8
723*5+84
723*5+84
723*5+842
723*5+842/-*-

Rule U
1
3
2
1
3
3
3
1
4
3
2
1
3
1
3
1
4&5

Infix to Postfix Conversion


Algorithm
create a stack and push the bottom-marker $
onto stack perform the following steps forever (until
exit out of it)
set x = nextToken(E)
if x = end-of-input
pop all
operators off the stack and output
(except the
marker $)
exit out of the loop
else if x = operand, output x
else if x = )
pop all operators
off stack and output each
until (; pop ( off
but dont output it
else pop all operators off
stack as long as their
ISP ICP(x)
push x onto stack

Balanced Symbol Checking


In processing programs and working
with computer languages there are
many instances when symbols must be
balanced
{},[],()
A stack is useful for checking symbol
balance. When a closing symbol is found it
must match the most recent opening
symbol of the same type.

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

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
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

[
(
{
{

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


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 3-4-5*3 is
3 4 - 5 3 * -

Evaluation of Postfix
Expressions

Easy to do with a stack


given a proper postfix expression:
get the next token
if it is an operand push it onto the stack
else if it is an operator

pop the stack for the right hand operand


pop the stack for the left hand operand
apply the operator to the two operands
push the result onto the stack

when the expression has been exhausted


the result is the top (and only element) of
the stack

Evaluate

3 4 - 5 3 * -

Found operand so push


Found operand so push
Found operator so pop two values,
apply operand, and push the result
4

s.push(3);
3
s.push(4);
right = s.pop(); // found operator - so pop
left = s.pop();
-1
s.push(left - right);
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);
s.push(3);
right = s.pop();
left = s.pop();
s.push(left * right);
5 * 3

5
-1

15
-1

The Stack has 2 values


Only one token remains

Continue with 15
-1

left = s.pop(); // found operator right = s.pop();


s.push(left - right);
-16
-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 * -

Queue

Queue
A queue is a finite sequence of elements in
which:
Insertion occurs only at the back;
Deletion occurs only at the front.

Queues provide First In First Out (FIFO)


access to elements could also say Last In Last Out
(LILO)

Can visualize a queue as a


line of customers waiting for
service
The next person to be served
is the one who has waited
the longest
New elements are placed at

A Conceptual View of a
Queue
Rear of Queue
(or Tail)
Adding an Element

Front of Queue
(or Head)
Removing an Element

67

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
(Dequeue)

front

rear

Insert
(Enqueue)

Enqueue and Dequeue


Enqueue Matt Enqueue Andrew
Matt

Front

Matt

Back

Front

Andrew

Back

Front

Matt

Front

Dequeue
Andrew

Enqueue Samira

Samira

Back

Andrew

Samira

Back

/**
* 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
enqueue(5)
enqueue(3)
dequeue()
enqueue(7)
dequeue()
front()
dequeue()
dequeue()
isEmpty()
enqueue(9)
enqueue(7)
size()
enqueue(3)
enqueue(5)
dequeue()

Output

3
7
7
error
true

Q
(5)
(5, 3)
(3)
(3, 7)
(7)
(7)
()
()
()
(9)
(9, 7)
(9, 7)
(9, 7, 3)
(9, 7, 3, 5)
(7, 3, 5)

75

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
Nave way
When enqueuing, the front index is always
fixed and the back index moves forward in the
array.

back

front

front

Enqueue(3)

back

back

Enqueue(6)

front
Enqueue(9)

Array implementation of queues


cont
Nave way
When dequeuing, the element at the front of queue
is removed. Move or shift all the elements after it
by one position. if size were 999, then 998 moves
would be necessary (A bad algorithm for remove

back

back

front
Dequeue()

front
Dequeue()

back =
-1

front
Dequeue()

Array implementation of queues cont


Better way
When an item is enqueued, make the back
index move forward.
When an item is dequeued, the front index
moves by one element towards the back of
the queue (thus removing the front item, so
no copying to neighboring elements is
needed).

Array implementation of
queues
A queue is a first in, first out (FIFO) data
structure
This is accomplished by inserting at one end
(the back) and deleting from the other (the
front)
0
1
2
3
4
5
6
7
myQueue:
front = 0

17

23

97

44
back = 3

To insert: put new element in location 4, and set back to 4


To delete: take element from location 0, and set front to 1

Array implementation of queues cont


back = 3

front = 0
Initial queue:

17

23

97

44

After insertion:

17

23

97

44

333

23

97

44

333

After deletion:
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)

myQueue:

44

55

back = 1

5
11

6
22

7
33

front = 5

Elements were added to this queue in the


order 11, 22, 33, 44, 55, and will be removed
in the same order
Use: front = (front + 1) % myQueue.length;
and: back = (back + 1) % myQueue.length;

Full and empty queues


If the queue were to become completely full, it
would look like this:
myQueue:

44

55

66

77

88

11

rear = 4

22

33

front = 5

If we were then to remove all eight elements,


making the queue completely empty, it would
look like this:
0
1
2
3
4
5
6
7
myQueue:
rear = 4

front = 5

This is a problem! (same) How to determine it

Full and empty queues:


solutions
Solution #1: Keep an additional variable
myQueue:

44

55

66

77

88

11

count = 8

rear = 4

6
22

7
33

front = 5

Solution #2: Keep a gap between elements:


consider the queue full when it has n-1
elements
myQueue:

44

55

66

77

rear = 3

5
11

6
22

7
33

front = 5

Applications of Queues
Operating systems use queues to
sequence tasks waiting for a scarce
resource
Printer queue
Tasks waiting for CPU

Simulation of physical systems


uses queues to simulate any
first-in first-out (FIFO) system
Supermarket checkouts
Tollbooths

85

Vous aimerez peut-être aussi