# Elementary Data Structures CS 110: Data Structures and Algorithms First Semester, 2010-2011.

## Presentation on theme: "Elementary Data Structures CS 110: Data Structures and Algorithms First Semester, 2010-2011."— Presentation transcript:

Elementary Data Structures CS 110: Data Structures and Algorithms First Semester, 2010-2011

Learning Objectives ► Explain and implement Stacks and Queues ► Analyze implementations in terms of efficiency

Elementary Data Structures ► Stack ► container of elements that are inserted and removed last-in first-out (LIFO) ► Queue ► container of elements that are inserted and removed first-in first-out (FIFO)

Stack ► Last-in, First-out (LIFO) structure ► Operations ► push: add element into the stack ► pop: remove & return topmost element ► top: return topmost element ► isEmpty: check if the stack has no elements ► size: return number of elements in the stack ► Sample uses ► "Back" button of a browser, "Undo" operation, function/method calls

Stack Interface public interface Stack { public int size(); public boolean isEmpty(); public void push( Object o ); public Object top() throws EmptyStackException; public Object pop() throws EmptyStackException; } public class EmptyStackException extends RuntimeException { }

Array Implementation public class ArrayStack implements Stack { private int top = -1; private Object S[];... } xyzw 3 top...

Array Implementation Details ► An array of objects stores the elements ► An integer field points to the topmost element ► Value of top is –1 when the stack is empty ► A constant indicates the size/capacity of the array ► Throw a StackFullException when a push is attempted on a full array

ArrayStack Class public class ArrayStack implements Stack { public static final int CAPACITY = 1000; private Object S[]; private int top; public ArrayStack() { S = new Object[CAPACITY]; top = -1; } public boolean isEmpty() { return (top < 0); } … }

ArrayStack Class continued public class ArrayStack implements Stack { … public int size() { return (top + 1); } public void push(Object obj) throws FullStackException { if (size() == CAPACITY) throw new FullStackException(); S[++top] = obj; } … } public class FullStackException extends RuntimeException { }

ArrayStack Class continued public class ArrayStack implements Stack { … public Object top() throws EmptyStackException { if (isEmpty()) throw new EmptyStackException(); return S[top]; } public Object pop() throws EmptyStackException { if (isEmpty()) throw new EmptyStackException(); return S[top--]; } … }

Garbage Collection ► After a pop() operation, array still contains reference to popped element ► Succeeding push() operations will override such references but it is not certain whether pushes will occur after the pops ► Better to set the reference to null so that the object is garbage-collected when no longer in use

Improved pop() Method public class ArrayStack implements Stack { … public Object pop() throws EmptyStackException { Object elem; if (isEmpty()) throw new EmptyStackException(); elem = S[top]; S[top--] = null; // dereference S[top] for garbage collection. return elem; } … }

Using the Stack Stack s1 = new ArrayStack(); String temp; s1.push( "easy" ); s1.push( "this" ); temp = (String) s1.pop(); System.out.print( temp ); s1.push( "is" ); s1.push( "class" ); while ( !s1.isEmpty() ) { temp = (String) s1.pop(); System.out.print( " "+ temp ); } System.out.println(); Cast object to String OK because Strings are Objects

Stack of ints Stack s2 = new ArrayStack(); s2.push( 5 ); s2.push( 2 ); s2.push( 3 ); int num = (Integer) s2.pop(); System.out.println( num ); Allowed in Java 1.5 because primitive type values are "auto-boxed" Cast object to Integer type (not int) Note: In previous Java versions, s2.push( new Integer( 2 ) ); num = ( (Integer) s2.pop() ).intValue();

Time Complexity Analysis ► push() :O(1) ► pop() :O(1) ► isEmpty() :O(1) ► size() :O(1) ► top() :O(1)

Array Implementation Alternative ► Make top variable point to next available array position instead of actual topmost element ► top = 0 when empty ► top represents size x 4 top yzw...

Problems with ArrayStack ► CAPACITY needs to be specified ► Consequences ► stack may fill up (when size() == MAX ) ► memory is wasted if actual stack consumption is way below maximum ► Need a more "dynamic" implementation

Linked List Implementation y top zw null A stack as a sequence of nodes

The Node Class public class Node { private Object element; private Node next; public Node( Object e, Node n ) { element = e; next = n; } public Object getElement() … public Node getNext() … public void setElement( Object newElem ) … public void setNext( Node newNext ) … } y

Linked List Implementation ► Stack is represented by a Node reference (called top) ► This reference is null when stack is empty ► Top refers to the top element only but links in each node keep the elements together ► An integer field represents the number of elements in the stack

NodeStack Class public class NodeStack implements Stack { private Node top; private int size; public NodeStack() { top = null; size = 0; } public boolean isEmpty() { return (top == null); } … }

NodeStack Class continued public class NodeStack implements Stack { … public int size() { return size; } public void push( Object obj ) { Node v = new Node( obj, top ); top = v; size++; } … }

Push Operation y top zw null 3 size

Push Operation y top zw null 3 size x Create node

Push Operation y top zw null 4 size x Update top and size

NodeStack Class continued public class NodeStack implements Stack { … public Object top() throws EmptyStackException { if ( isEmpty() ) throw new EmptyStackException(); return top.getElement(); } public Object pop() throws EmptyStackException { if ( isEmpty() ) throw new EmptyStackException(); Object temp = top.getElement(); top = top.getNext(); size--; return temp; } … }

Pop Operation y top zw null 4 size x

Pop Operation y top zw null 4 size x Get top element temp

Pop Operation y top zw null 3 size x Update top and size temp

Pop Operation y top zw null 3 size x Node automatically disposed temp

x Pop Operation y top zw null 3 size Return element

Using the NodeStack Stack s2 = new NodeStack(); s2.push( 5 ); s2.push( 2 ); s2.push( 3 ); int num = (Integer) s2.pop(); System.out.println( num ); Only this line is changed

Time Complexity Analysis ► push() :O(1) ► pop() :O(1) ► isEmpty() :O(1) ► size() :O(1) ► top() :O(1)

ArrayStack versus NodeStack ► NodeStack uses only the memory that it needs at any given time ► NodeStack has no size limit (just the system’s memory) – FullStackException not thrown ► ArrayStack’s implementation is simpler ► Which implementation is more efficient?

Managing Multiple Implementations ► Note that we now have two implementations of a Stack: public class ArrayStack implements Stack { … } public class NodeStack implements Stack { … } ► Consider what code needs to be changed if we shift between implementations ► It would be preferable if the code that uses the stack does not need to be updated

A StackFactory Class ► Use a separate class that produces Stack objects public class StackFactory { public static Stack createStack() { return new ArrayStack(); // or return new NodeStack(); } ► Advantage: ► if you want to change your implementation, you just need to change StackFactory ► you don’t need to change all calls to new ArrayStack in all your code!

Using a StackFactory Stack s2 = StackFactory.createStack(); s2.push( 5 ); s2.push( 2 ); s2.push( 3 ); int num = (Integer) s2.pop(); System.out.println( num ); this line need not be changed even if the stack implementation changes

Queue ► First-in, First-out (FIFO) structure ► Operations ► enqueue: insert element at rear ► dequeue: remove & return front element ► front: return front element ► isEmpty: check if the queue has no elements ► size: return number of elements in the queue ► Sample use ► handling requests and reservations

The Queue Interface public interface Queue { public int size(); public boolean isEmpty(); public void enqueue( Object o ); public Object front() throws EmptyQueueException; public Object dequeue() throws EmptyQueueException; } public class EmptyQueueException extends RuntimeException { }

Array Implementation Possibilities ► On enqueue, place element in the next available slot; on dequeue, remove element at position 0 and move all other elements to the left ► Dequeue takes O(n) time ► Have integer pointers to front and rear, increment rear on enqueue, increment front on dequeue, so that both operations are O(1)

Array Implementation of a Queue ► An Object array and two integers ► front: index of first element in queue ► rear: index of first FREE element in queue 4 rear... 0 front

ArrayQueue public class ArrayQueue implements Queue { public static final int CAPACITY = 1000; private Object s[]; private int front, rear; public ArrayQueue() { s = new Object[CAPACITY]; front = rear = 0; }... }

isEmpty and Enqueue public class ArrayQueue implements Queue {... public boolean isEmpty() { return ( front == rear ); } public void enqueue( Object o ) throws FullQueueException { if ( rear == CAPACITY ) throw new FullQueueException(); s[rear++] = o; }... } public class FullQueueException extends RuntimeException { }

Enqueue Operation 3 rear... 0 front

Enqueue Operation 4 rear... 0 front Enqueued object

Dequeue public class ArrayQueue implements Queue {... public Object dequeue() throws EmptyQueueException { if ( isEmpty() ) throw new EmptyQueueException(); return s[front++]; } … }

Dequeue Operation 4 rear... 1 front Return this object

Dequeue Operation 4 rear... 1 front Remember to set reference in array to null null

Dequeue with Garbage Collection public class ArrayQueue implements Queue {... public Object dequeue() throws EmptyQueueException { if ( isEmpty() ) throw new EmptyQueueException(); Object data = s[front]; s[front] = null; front++; return data; }

Circular Array ► Suppose many enqueue operations followed by many dequeue operations ► Result: rear approaches CAPACITY but the queue is not really full ► Solution: Circular Array ► allow rear (and front) to "wrap around" the array (if rear = CAPACITY-1, incrementing rear means resetting it to 0)

Circular Array continued ► When is the array full? ► Simple answer: when (rear == front) ► Problem: this is the same condition as empty ► Solution: Reserve a slot ► full: when ( (rear+1) % CAPACITY == front) (one free slot left) ► empty: when ( rear == front ) ► Note: "wastes" a slot ► alternative: have a boolean field called hasElements ► full: when ( hasElements && (rear == front)) ► But not really better ► hasElements takes up extra space too ► Also, need to take care of hasElements in enqueue and dequeue

Revised Enqueue public class ArrayQueue implements Queue {... public void enqueue( Object o ) throws FullQueueException { if ((rear+1) % CAPACITY == front) throw new FullQueueException(); s[rear] = o; rear = (rear + 1) % CAPACITY; }... }

Revised Dequeue public class ArrayQueue implements Queue {... public Object dequeue() throws EmptyQueueException { if ( isEmpty() ) throw new EmptyQueueException(); Object data = s[front]; s[front] = null; front = (front + 1) % CAPACITY; return data; } … }

Completing the ArrayQueue Class public class ArrayQueue implements Queue {... public int size() { return (CAPACITY + rear – front) % CAPACITY; } … public Object front() throws EmptyQueueException { if ( isEmpty() ) throw new EmptyQueueException(); return s[front]; } … }

Time Complexity Analysis ► enqueue() :O(1) ► dequeue() :O(1) ► isEmpty() :O(1) ► size() :O(1) ► front() :O(1)

Dynamic Implementation ► Queue is represented by a linked sequence of nodes ► Two node references refer to front and rear element, respectively ► Use a size field to monitor number of elements

public class NodeQueue implements Queue { private Node front; private Node rear; private int size; } Linked List Implementation

Enqueue front null rear

Enqueue front rear null

Dequeue front null rear Return this object

NodeQueue Considerations ► Exercise: complete the NodeQueue class ► Note that the queue is empty when both front and rear are null ► Need to watch out for special cases ► Enqueue from an empty queue ► Dequeue from a single-element queue

Exercise: Balanced Parenthesis ► Write a program which takes in a string then outputs whether ( YES ) or not ( NO ) the parentheses are balanced. ► Only consider (),[],{} and <>. Ignore everything else. InputOutput ((A))YES ( c)YES { ]}NO (()NO ())NO

Exercise: Postfix Calculator ► Write a program which computes then prints the result of a postfix string or prints ERROR for an invalid string. ► Input numbers are single-digit for simplicity. InputOutput 12+3 32+4*20 1+2ERROR 90*2--ERROR

Download ppt "Elementary Data Structures CS 110: Data Structures and Algorithms First Semester, 2010-2011."

Similar presentations