# Queues Ellen Walker CPSC 201 Data Structures Hiram College.

## Presentation on theme: "Queues Ellen Walker CPSC 201 Data Structures Hiram College."— Presentation transcript:

Queues Ellen Walker CPSC 201 Data Structures Hiram College

Queue Process data in a “fair” way regarding wait time Access only “least recently added” item –When “least recently added” item is removed, the former 2nd least recently added item becomes available! Why is it called a queue? –Queue of people waiting for a bus –Queue of jobs waiting for a printer

Operations on a Queue Create an empty queue Is the queue empty? (isEmpty) Add a new item to the queue. (offer) Remove the item that was least recently added (remove or poll) Retrieve the item that was least recently added (peek or element)

Removing & Retrieving Front Element Removing front element –poll() - returns null if queue is empty –remove() - throws exception if queue is empty Retrieving front element without removing –peek() - returns null if queue is empty –element() - throws exception if queue is empty

Specification for a Queue Interface

Example Create an empty queue Offer “A” Offer “B” Remove (returns A) Offer “C” Remove (returns B) Peek (returns C)

LIFO vs. FIFO A queue is FIFO (first in, first out) –Queues are fair when someone has to wait A stack is a LIFO (last in, first out) data structure –New addition makes older items inaccessible –Stacks model “interruptions” in the real world (including getting back to what was interrupted…)

Reading and Printing a Line //A queue of characters Queue q = new LinkedList (); //Read a line (scIn is a Scanner for System.in) String theLine = scIn.nextLine(); for(int c=0;c { "@context": "http://schema.org", "@type": "ImageObject", "contentUrl": "http://images.slideplayer.com/13/4151477/slides/slide_8.jpg", "name": "Reading and Printing a Line //A queue of characters Queue q = new LinkedList (); //Read a line (scIn is a Scanner for System.in) String theLine = scIn.nextLine(); for(int c=0;c

Check a Palindrome with Queue and Stack boolean checkPalindrome(String theLine){ Stack s = new ArrayStack (); Queue q = new LinkedList (); //Put each character into both queue and stack for(int c=0;c { "@context": "http://schema.org", "@type": "ImageObject", "contentUrl": "http://images.slideplayer.com/13/4151477/slides/slide_9.jpg", "name": "Check a Palindrome with Queue and Stack boolean checkPalindrome(String theLine){ Stack s = new ArrayStack (); Queue q = new LinkedList (); //Put each character into both queue and stack for(int c=0;c

Checking a Palindrome (continued) //Check that forward (queue) and reverse (stack) //sequence of characters is the same while((!s.empty() && !q.isEmpty()){ char left = q.remove(); char right = s.pop(); if(left != right) return false; } return true; //both stack & queue are guaranteed same size }

Java’s List Implementation Java implements queue as a doubly-linked list (LinkedList class) Doesn’t matter which end is which, but Java uses head as front, tail as rear Allowing LinkedList to implement queue breaks the abstraction –Queue shouldn’t have iterators, size(), etc.

Single Linked Implementation Where should the front be? (easy to access & remove, inserting not necessary) Where should the back be? (easy to insert, direct access and removal not necessary) No real reason for either front or back to be anywhere but beginning or end of list.

Solution Since we need to update the item *before* the given item to delete (except special case at head of list), we should delete at the head. Therefore, list head = queue front List tail = queue back, but that’s ok because we’ll have the item before (old tail) for the insertion.

Example (List Implementation) Empty queue Enqueue ‘a’, Enqueue ‘b’, Enqueue ‘c’ Dequeue, Dequeue Enqueue ‘z’ abc c cz

Class Definition (data fields) Public class ListQueue extends AbstractQueue implements Queue { private Node front; private Node rear; //Insert inner Node class from LinkedList here private int size; // not strictly necessary … };

isEmpty & peek //Is the Queue empty? public boolean IsEmpty() { return (front == null); } //Get item from front public E peek() { if (isEmpty()) return null; else return front.data; }

Offer // offer (add to end of list) public boolean offer(E item){ Node newItem = new Node(item); if (isEmpty()) front = newItem; else rear.next = newItem; rear = newItem; }

poll //Dequeue and recover old front item Public E poll(){ E item = peek(); if (item == null) return null; //empty queue else{ front=front.next; if (front == null) rear = null; //removed last item } return item; }

Array Implementation Where should the front be? (easy to access & remove, inserting not necessary) Where should the back be? (easy to insert, direct access and removal not necessary) No real reason for either front or back to be anywhere but beginning or end of array.

Array Implementation Inserting at the beginning of the array would cause a great deal of shifting! Therefore, insert at end of array –Rear of queue is end of array –Front of queue is front of array Remove by moving the front pointer (like top for stack) Problem: once we’ve moved the front forward, we lose access to the space behind it!

Solution Use a “circular array” –Most of the time, it acts like a normal array –The item after element MAX-1 is element 0 –Use Mod (%) operation to implement this. One more problem… –How do we tell an empty array from a full array? –When the back pointer is one slot behind the front pointer, i.e. (back+1)%MAX = front, the array is either empty or full!

Empty vs. Full Array 1.Keep a count of the elements in the array Minimal space cost (1 integer), some time for each update 2.Keep one element free. When the queue is empty, (back+1)%MAX = front. When the queue is full (back+2)%MAX = front. Space cost is the size of 1 queue element. This can be (much) larger than an integer! 3.Keep a “full” flag Space & time costs similar to option #1.

Array Queue Implementation public class ArrayQueue extends AbstractQueue implements Queue { private E[] theData; private int front, rear; private int size, capacity; //choice 1 … }

Constructor & isEmpty Constructor creates a new array Public ArrayQueue(int initCapacity) { theData = (E[]) new Object[capacity]); capacity = initCapacity; front = 0; rear = capacity–1; } isEmpty uses size (really in abstractQueue) Public boolean isEmpty(){ return (size == 0); }

Offer public boolean offer(Itemtype item){ if (size == capacity) reallocate(); rear = (rear+1) % capacity; theData[rear] = item; size++; return true; }

Poll (and peek) Public E poll(){ if (isEmpty()) return null; E result = theData[front]; front = (front+1) %capacity; size--; return result; } //Peek is similar, but doesn’t change front or size.

Reallocate When the queue is full, make a new one (double size) and copy all the data Private void reallocate(){ //make new array int newCapacity = 2*capacity; E[] newData = (E[]) new Object[newCapacity]; int j=front; //continued on next slide

Reallocate (continued) //copy data to new array int j=front; for int (x=0;x { "@context": "http://schema.org", "@type": "ImageObject", "contentUrl": "http://images.slideplayer.com/13/4151477/slides/slide_29.jpg", "name": "Reallocate (continued) //copy data to new array int j=front; for int (x=0;x

Application: Simulation Simulate a real-life situation Make several simplifying assumptions –Time is divided into discrete time steps –One or more events happen at each time step Arrival events (e.g. customer arrives at bank) -- comes from input (time of arrival) Departure events (e.g. customer leaves bank) -- internally determined from when transaction begins and transaction time.

Bank example with Queue We want to measure how long customers wait at the bank. When a customer arrives, an arrival event is processed. Since customers should be processed in order, they wait in a queue Assume that each transaction takes a fixed amount of time. When time is up, the customer being processed leaves, and the next customer (front of the queue) takes their place.

Using the Simulation for Decision Making Vary the number of tellers - how does the wait time vary? Consider different types of “teller transactions” with different transaction times Should we have an “express lane”? If we have multiple tellers, should each have its own queue?

A simple pseudocode Read the first arrival For (time=0;time { "@context": "http://schema.org", "@type": "ImageObject", "contentUrl": "http://images.slideplayer.com/13/4151477/slides/slide_33.jpg", "name": "A simple pseudocode Read the first arrival For (time=0;time

Two data structures Event list –Sorted by event time –Includes arrivals and departures –List, not queue (why)? Customer queue –Customers enter when they arrive if the teller is busy –Customer at front of queue “goes to the teller” when the previous customer departs

Implementing the “teller” We don’t need a specific data structure for the teller –When a customer “goes to the teller”, a departure event for that customer is created –Time of departure is based on estimated transaction time –When the departure event is processed, that customer “leaves the teller”, and a new customer will be taken from the front of the queue

Searching a Graph with a Queue Given connections among cities, find a path from A to B Revise our stack algorithm to use a queue: q.offer (Start) for each city visible from q.peek() if the city is End, recover and return the path if the city is not already on the queue, mark city’s predecessor as q.peek() q.offer( the city ) q.remove().