implementing stacks & queues

26
IKI 10100: Data Structures & Algorithms Ruli Manurung (acknowledgments to Denny & Ade Azurat) 1 Fasilkom UI Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6 th Mar 2007 Implementing Stacks & Queues

Upload: arty

Post on 14-Jan-2016

71 views

Category:

Documents


0 download

DESCRIPTION

Implementing Stacks & Queues. Outline. ADT Stacks Basic operations Examples of use Implementations Array-based and linked list-based ADT Queues Basic operations Examples of use Implementations Array-based and linked list-based Stack Applications Balanced Symbol Checker - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Implementing Stacks & Queues

IKI 10100: Data Structures & Algorithms

Ruli Manurung(acknowledgments to Denny & Ade Azurat)

1

Fasilkom UI

Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Implementing Stacks & Queues

Page 2: Implementing Stacks & Queues

2Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

ADT Stacks Basic operations Examples of use Implementations

• Array-based and linked list-basedADT Queues Basic operations Examples of use Implementations

• Array-based and linked list-basedStack Applications Balanced Symbol Checker Postfix Machines

Summary

Outline

Page 3: Implementing Stacks & Queues

3Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Linear Data Structures

A collection of components that are arranged along one dimension, i.e in a straight line, or linearly.

Stack: a linear data structure where access is restricted to the most recently inserted item.

Queue: a linear data structure where access is restricted to the least recently inserted item.

Both of these abstract data types can be implemented at a lower level using a list: either an array or a linked list.

Page 4: Implementing Stacks & Queues

4Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Stack

The last item added is pushed (added) to the stack.

The last item added can be popped (removed) from the stack.

The last item added can be topped (accessed) from the stack.

These operations all take constant time: O(1).

A typical stack interface:

void push(Thing newThing);

void pop();

Thing top();

Page 5: Implementing Stacks & Queues

5Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Stack Implementation: Array

A stack can be implemented as an array A and an integer top that records the index of the top of the stack.

For an empty stack, set top to -1.

When push(X) is called, increment top, and write X to A[top].

When pop() is called, decrement top.

When top() is called, return A[top].

Page 6: Implementing Stacks & Queues

6Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Example

top(-1)

A top(0) A

B top(1)

Push A Push B

MyStack myStack = new MyStack();

myStack.push(A);

myStack.push(B);

Page 7: Implementing Stacks & Queues

7Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Array Doubling

When array-based stack is constructed, instantiate an array with a “default” size.

When the array underlying the stack is full (not the stack itself!), we can increase the array through array doubling.

Allocate a new array twice the size, and copy the old array to the first half of the new array:

Thing[] newA = new Thing[oldA.length*2];

for(int ii=0; ii<oldA.length; ii++) newA[ii] = oldA[ii];

oldA = newA;

Page 8: Implementing Stacks & Queues

8Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Running Time

Without array doubling, all stack operations take constant time – O(1).

With array doubling, push() may be O(N), but this happens quite rarely: array doubling due to data size N must be preceded by N/2 push() non-doubling calls. Effectively, still constant time Amortization.

Page 9: Implementing Stacks & Queues

9Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Stack Implementation: Array

public class MyArrayStack<T>{ private T[] array; private int topOfStack; private static final int DEFAULT_CAPACITY = 10;

public MyArrayStack() … public boolean isEmpty() … public void makeEmpty() … public T top() … public void pop() … public T topAndPop() … public void push(T x) …

private void doubleArray() …}

Page 10: Implementing Stacks & Queues

10Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Stack Implementation: Linked List

First item in list = top of stack (if empty: null)push(Thing x): Create a new node containing x Insert it as the first elementpop(): Delete first item (i.e. move “top” to the second

item)top(): Return the data of the first element

d c b a

topOfStack

Page 11: Implementing Stacks & Queues

11Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Stack Implementation: Linked List

public class MyLinkedListStack<T>{ private ListNode<T> topOfStack;

public MyLinkedListStack() … public boolean isEmpty() … public void makeEmpty() … public T top() … public void pop() … public T topAndPop() … public void push(T x) …}

Page 12: Implementing Stacks & Queues

12Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Queue

Last item added is enqueued (added) to the back.First item added is dequeued (removed) from the front.First item added can be accessed: getFront.These operations all take constant time – O(1).

A typical queue interface:void enqueue(Thing newThing);void dequeue();Thing getFront();

Page 13: Implementing Stacks & Queues

13Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Queue Implementation: Simple Idea

Store items in an array A

Maintain index: back

Front of queue = A[0]

Back of queue = A[back]

Enqueue is easy & fast: store at A[back], back++

Dequeue is inefficient: A[1] to A[back] needs to be shifted (and back--) O(N)

X

back

X Y

back

X Y Z

back

Y Z

back

enqueue(X) enqueue(Y) enqueue(Z) dequeue()

Page 14: Implementing Stacks & Queues

14Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Queue Implementation: Better Idea

Add another index: front, which records the front of the queue

Dequeue is now done by incrementing front

Both enqueue and dequeue are now O(1).

But what happens if enqueue and dequeue array.length-1 items?

X Y Z

back

Y Z

back

enqueue(X)enqueue(Y)enqueue(Z) dequeue()

front front

Z

back

dequeue()

front

Page 15: Implementing Stacks & Queues

15Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Queue Implementation: “Circular” Array

After the array.length-1-th item is enqueued, the underlying array is full, even though the queue is not logically, it should be (almost?) empty.

Solution: wraparound

Re-use cells at beginning of array that are ‘empty’ due to dequeue.

When either front or back is incremented and points “outside array” (≥array.length), reset to 0.

Page 16: Implementing Stacks & Queues

16Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Circular Example

Both front and back indexes “wraparound” the array. Think of the array as a circle…

P Q R

front back

P Q R S

frontback

P Q R S

front

T

back

Q R S

front

T

back

R S

front

T

back

S

front

T

back

T

front back

Page 17: Implementing Stacks & Queues

17Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Java Implementation

Fairly straightforward. Basically, maintain Front Back Number of items in queue

When is the underlying array really full?

How do we do array doubling?

Page 18: Implementing Stacks & Queues

18Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Queue Implementation: Array

public class MyArrayQueue<T>{ private T[] array; private int front,back,currentSize; private static final int DEFAULT_CAPACITY = 10;

public MyArrayQueue() … public boolean isEmpty() … public void makeEmpty() … public T getFront() … public void dequeue() … public T getFrontAndDequeue() … public void enqueue(T x) …

private void doubleQueue() … private int increment(int x) …}

Page 19: Implementing Stacks & Queues

19Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Queue Implementation: Linked List

Maintain 2 node references: front & back

An empty queue: front = back = null.

enqueue(Thing X): Create a new node N containing X If queue empty: front = back = N Else append N and update back

dequeue(): Delete first item (referenced by front)

getFront(): Return data of first element

a b c d

front back

Page 20: Implementing Stacks & Queues

20Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Queue Implementation: Linked List

public class MyLinkedListQueue<T>{ private ListNode<T> front; private ListNode<T> back;

public MyLinkedListQueue() … public boolean isEmpty() … public void makeEmpty() … public T getFront() … public void dequeue() … public T getFrontAndDequeue() … public void enqueue(T x) …}

Page 21: Implementing Stacks & Queues

21Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Stack Application: Balanced Symbols

Java uses pairs of symbols to denote blocks: ( and ) { and } [ and ]

An opening symbol must be matched with a closing symbol: { [ ( ) ] } is OK { ( [ ) ] } is NOT OK

A closing symbol, e.g. ‘)’, must match the most recently seen opening symbol, e.g. ‘(‘.

This can be done using a stack.

Page 22: Implementing Stacks & Queues

22Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Balanced Symbol Checker Algorithm

Make an empty stack

Read symbols: If symbol is an opening symbol, push onto stack. If symbol is a closing symbol:

• If stack is empty, report error!

• Else, (top and) pop stack. If popped symbol is not a matching opening symbol, report error!

At the end, if the stack is not empty, report error!

Page 23: Implementing Stacks & Queues

23Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Say we are given an arithmetic expression, and we are asked to evaluate it.Typically, we use infix expressions, of the form operand1 OPERATOR operand2Example: 1 + 2 4 * 3

To process infix expressions we need precedence and associativity: 1 + 2 * 3 10 - 4 - 3 2 ^ 3 ^ 3 1 - 2 - 4 ^ 5 * 3 * 6 / 7 ^ 2 ^ 2

We use brackets: (1-2)-((((4^5)*3)*6)/(7^(2^2)))

Stack Application: Simple Calculator

Page 24: Implementing Stacks & Queues

24Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Postfix Notation

Typically, we use postfix expressions, of the form operand1 operand2 OPERATOR

Example: 1 2 + 4 3 *

With postfix expressions, precedence is unambiguous: 1 - 2 - 4 ^ 5 * 3 * 6 / 7 ^ 2 ^ 2, or (1-2)-((((4^5)*3)*6)/(7^(2^2))), becomes 1 2 - 4 5 ^ 3 * 6 * 7 2 2 ^ ^ / -

Page 25: Implementing Stacks & Queues

25Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Postfix Machines

A postfix machine evaluates a postfix expression: If an operand is seen, push it onto stack If an operator is seen, pop appropriate number of

operands, evaluate operator, push result onto stack

When the complete postfix expression is evaluated, the stack should contain exactly one item: the result.

Page 26: Implementing Stacks & Queues

26Ruli Manurung (Fasilkom UI) IKI10100: Lecture 6th Mar 2007

Both versions, array and linked-list, run in O(1)

Linked-list implementation requires extra overhead due to next reference at each node

(Circular) array implementation of queues can be quite tricky

Array space doubling needs memory at least 3x size of actual data.

Summary