1 / 21

Implementing Stacks & Queues

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. Linear Data Structures.

latona
Download Presentation

Implementing Stacks & Queues

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Implementing Stacks & Queues

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

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

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

  5. 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 topto -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].

  6. Push A Push B B top(1) A top(0) A top(-1) Example MyStack myStack = new MyStack(); myStack.push(A); myStack.push(B);

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

  8. 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/2push()non-doubling calls. • Effectively, still constant time Amortization.

  9. 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() … }

  10. d c b a 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 element • pop(): • Delete first item (i.e. move “top” to the second item) • top(): • Return the data of the first element topOfStack

  11. 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) … }

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

  13. X X Y X Y Z Z Y back back back back 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) enqueue(X) enqueue(Y) enqueue(Z) dequeue()

  14. Y X Y Z Z Z back back front front front back 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). enqueue(X) enqueue(Y) enqueue(Z) dequeue() dequeue() Question: what happens if we enqueue then dequeuearray.length-1 items?

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

  16. front back back front back back front back front back front front Q T R Q P P Q R S T R S T R R Q T P S T S S front back Circular Example • Both front and back indexes “wraparound” the array. Think of the array as a circle…

  17. 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?

  18. 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) … }

  19. a b c d 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 front back

  20. 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) … }

  21. Summary • 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.

More Related