Top Banner
7-1 Chapter 7 Stacks and Queues Data Structures and Design in Java © Rick Mercer
56
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 7 stacksqueues

7-1

Chapter 7Stacks and Queues

Data Structures and Design in Java © Rick Mercer

Page 2: 7 stacksqueues

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

Page 3: 7 stacksqueues

7-3 Using a Stack Object

// Construct an empty stack using Interface in bookGenericStack stackOfInts = new ArrayStack( );

// Push three string values onto the stackstackOfInts.push( new Integer( 1 ) );stackOfInts.push( new Integer( 2 ) );stackOfInts.push( new Integer( 3 ) );

// Show each element before removed in a LIFO orderwhile( !stackOfInts.isEmpty( ) ){ // Print the value as it is removed from top of stack System.out.println( stackOfInts.pop( ) );}

Page 4: 7 stacksqueues

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

Page 5: 7 stacksqueues

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

Page 6: 7 stacksqueues

7-6Cast 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 );}OutputZeke has $300.0Huey has $200.0Barb has $100.0

Page 7: 7 stacksqueues

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

Page 8: 7 stacksqueues

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"

Page 9: 7 stacksqueues

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

Page 10: 7 stacksqueues

7-10 Balancing Symbolsopeners [ ( { 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

Page 11: 7 stacksqueues

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

Page 12: 7 stacksqueues

7-12Example 1: Reporting errors on unclosed symbols

1. Make an empty stack named s2. 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

Page 13: 7 stacksqueues

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

[ ( { {

Page 14: 7 stacksqueues

7-14Pop the first closerDo 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 ) } }

Page 15: 7 stacksqueues

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

} }

Page 16: 7 stacksqueues

7-16Pop 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 '}'.

Page 17: 7 stacksqueues

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.

Page 18: 7 stacksqueues

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

Page 19: 7 stacksqueues

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

Page 20: 7 stacksqueues

7-20 A stack of String Objects

null

null

nullnull

null

null

null

null

null

null

my_top = -1

Construct an empty Stack

"A""B"null

null

null

null

null

null

null

null

my_top = 1

push("A")push ("B")

"A"

null

null

null

null

null

null

null

null

null

my_top = 0

pop()

null

null

null

null

null

null

null

null

nullnull

my_top = -1

pop()

[0]

[1]

[0]

[1]

[0]

[1]

[0][1][2][3]

...

[9]

Page 21: 7 stacksqueues

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

}

Page 22: 7 stacksqueues

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

}

Page 23: 7 stacksqueues

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

}

Page 24: 7 stacksqueues

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];}

Page 25: 7 stacksqueues

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)

Page 26: 7 stacksqueues

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

}

Page 27: 7 stacksqueues

7-27Example 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 / +

Page 28: 7 stacksqueues

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

Page 29: 7 stacksqueues

7-29 Evaluate 3 4 - 5 3 * -

s.push( 3 ); s.push( 4 ); op2 = s.pop( ); // found operator - so popop1 = 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 pushFound operand so pushFound operator so pop two values, apply operand, and push the result

Page 30: 7 stacksqueues

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 valuesOnly one token remains

15

5

3

-1

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

-1

Page 31: 7 stacksqueues

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 -16Now evaluate 2 3 4 * 5 * -

15

-1

-16

Page 32: 7 stacksqueues

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

Page 33: 7 stacksqueues

7-33Part of an algorithm for creating a postfix "String"

Let postfix be a String that is "" and stack be an empty StackFor each token in the input stream {

if operand: Immediately concatenate operand to postfixif open parentheses: Push '(' on the stackif 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 expressionNote: Left parentheses are treated as a high precedence operator on input but as a low

precedence operator when on the stack

Page 34: 7 stacksqueues

7-34Queues: Containers with First in first out access

A Queue is another name for waiting lineEx: 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 queueQueue have First In First Out (FIFO) access

to elements could we also say Last In Last Out (LILO)?

Page 35: 7 stacksqueues

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

Page 36: 7 stacksqueues

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

Page 37: 7 stacksqueues

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

Page 38: 7 stacksqueues

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( );}

Page 39: 7 stacksqueues

7-39Java 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 {}

Page 40: 7 stacksqueues

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

Page 41: 7 stacksqueues

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

Page 42: 7 stacksqueues

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

Page 43: 7 stacksqueues

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

Page 44: 7 stacksqueues

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

Page 45: 7 stacksqueues

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

Page 46: 7 stacksqueues

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

Page 47: 7 stacksqueues

7-47

"e"

But what happens next when back equals array.length?

enqueue("e") "a" "b" "c" "d"

front backback is at the last array indexBut this queue is not fullWhere 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

? ________________________________ ?

Page 48: 7 stacksqueues

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

Page 49: 7 stacksqueues

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?

Page 50: 7 stacksqueues

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

Page 51: 7 stacksqueues

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)];

Page 52: 7 stacksqueues

7-52Correct 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 frontMust waste one array element no big deal

Page 53: 7 stacksqueues

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

Page 54: 7 stacksqueues

7-54Quiz: Implement a Queue class with a LinkedList instance variable

import java.util.*; // For class LinkedListpublic class LinkedListQueue implements Queue{ private LinkedList my_data; public LinkedQueue( ) { // 1.

} public void enqueue( Object element ) { // 2.

}

Page 55: 7 stacksqueues

7-55 Implement getFront & isEmpty

public Object getFront() { // 3. Assume queue is not empty

} public boolean isEmpty( ) { // 4.

}

// 5. Completely implement dequeue

Page 56: 7 stacksqueues

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