Queues Cmput Lecture 19 Department of Computing Science University of Alberta ©Duane Szafron 2000 Some code in this lecture is based on code from the book: Java Structures by Duane A. Bailey or the companion structure package Revised 2/24/00
©Duane Szafron About This Lecture In this lecture we will learn about an implementation of a linear data called a Queue.
©Duane Szafron Outline Queue in the Structure Container Hierarchy Queue Interface Maze - An example of using a Queue List Implementation of Queue Vector Implementation of Queue
©Duane Szafron Linear Container Hierarchy In the structure package the following interface hierarchy appears. Store Linear StackQueue In the java.* packages there is no Queue as an interface or as a class.
©Duane Szafron Structure Interface - Store public interface Store { public int size (); //post: returns the number of elements contained in // the store. public boolean isEmpty (); // post: returns the true iff store is empty. public void clear (); // post: clears the store so that it contains no // elements. } code based on Bailey pg. 18
©Duane Szafron Structure Interface - Linear public interface Linear extends Store { public void add (Object anObject); // pre: anObject is non-null // post: the object is added to the container. The // consistent replacement policy is not specified public Object peek (); // pre: container is not empty // post: returns the next object to be removed, but does in // not remove it public Object remove (); // pre: container is not empty // post: removes an object from the container and returns it } code based on Bailey pg. 127
©Duane Szafron Structure Interface - Queue 1 public interface Queue extends Linear { public void add (Object anObject); // post: the object is added at the tail. It will be // removed after all elements in front of it. public void enqueue (Object anObject); // post: the object is added at the tail. It will be // removed after all elements in front of it. public Object remove (); // pre: queue is not empty // post: the head of the queue is removed and returned code based on Bailey pg. 137
©Duane Szafron Structure Interface - Queue 2 public Object dequeue (); // pre: queue is not empty // post: the head of the queue is removed and returned public Object peek (); // pre: queue is not empty // post: returns the element at the head of the queue, // but does not remove it } code based on Bailey pg. 137
©Duane Szafron Queue Example - Maze Algorithm Like Stacks, Queues can also be used to store unsearched paths. 0 S F Repeat as long as the current square is not null and is not the finish square: –“Visit” the square. –Enqueue one square on the queue for each unvisited legal move from the current square. –Dequeue the queue into the current square or bind the current square to null if the stack is empty. If the current square is the goal we are successful, otherwise there is no solution
©Duane Szafron Queue Example - Searching The algorithm seems the same so what is the difference between using a Stack and a Queue? When a Stack is used, the search goes as deep along a single path as possible, before trying another path. When a Queue is used, the search expands a frontier of nodes equidistant from the start. 0 S F S F Stack Search Queue Search
©Duane Szafron Queue Example - Searching 0 S F S F Stack Search Queue Search
©Duane Szafron Queue Example - Maze Trace 1 P0 P1 0 S F P1 P3 P2 0 S F P2 P5 P4 0 S F P3 P6 P5 0 S F P4 P7 P6 0 S F P5 P8 0 S F P7 P6
©Duane Szafron Queue Example - Maze Trace 2 P5 P8 P7 0 S F P6 P9 P8 P7 0 S F P7 P9 P8 0 S F P8 P10 0 S F P9 P11 0 S F P10 Success! P10 P11 0 S F
©Duane Szafron Maze Program Same program as in the Stack lecture, except replace the line: todo = new StackList (); // A class that implements Stack by: todo = new QueueList (); // A class that implements Queue
©Duane Szafron List-Based Queues We can implement a Queue using a DoublyLinkedList or a CircularLinkedList. We do not use a SinglyLinkedList since operations on the tail take time proportional to the length of the list. As the Queue grows and shrinks, so does the list. The time for adding or removing a single element is always the same constant time. There are two extra link spaces required for each element. The implementation is simple, few mistakes are made.
©Duane Szafron QueueList - State and Constructors public class QueueList implements Queue { /* An implementation of the Queue Interface that uses a DoublyLinkedList to store the Stack elements. */ // Instance Variables // protected List data; public QueueList () { // post: initialize the Stack to be empty this.data = new DoublyLinkedList(); //or CircularLinkedList } code based on Bailey pg. 140
©Duane Szafron QueueList - Linear Interface 1 public void add (Object anObject) { // post: the object is added at the tail. It will be // removed after all elements in front of it. this.data.addToTail(anObject); } public Object remove () { // pre: queue is not empty // post: the head of the queue is removed and returned return this.data.removeFromHead(); } code based on Bailey pg. 141
©Duane Szafron QueueList - Linear Interface 2 public Object peek () { // pre: queue is not empty // post: returns the element at the head of the queue, // but does not remove it Assert.pre(!this.isEmpty(), “Queue is not empty”); return this.data.peek(); } code based on Bailey pg. 142
©Duane Szafron QueueList - Queue Interface public void enqueue (Object anObject) { // post: the object is added at the tail. It will be // removed after all elements in front of it. this.add(anObject); } public Object dequeue () { // pre: queue is not empty // post: the head of the queue is removed and returned return this.remove(); } code based on Bailey pg. 141
©Duane Szafron QueueList - Store Interface public int size(); //post: returns the number of elements contained in the store. return this.data.size(); } public boolean isEmpty(); // post: returns the true iff store is empty. return this.size() == 0; } public void clear(); // post: clears the store so that it contains no elements. this.data.clear(); } code based on Bailey pg. 142
©Duane Szafron Vector-Based Queues We can implement a Queue using a single Vector. However, this implementation is not time efficient. Adding an element to the Queue results in adding an element to the end of the Vector which takes constant time (except when the Vector must grow). However, removing an element from the Queue results in removing the zeroth element of the Vector which takes time proportional to the length of the Vector (since all elements after the zeroth must be moved to the left). Since this implementation has such poor performance, we will not use it.
©Duane Szafron Array-Based Queues We can implement a Queue using a single Array if we know in advance the maximum size of the Queue. The naïve implementation of storing the head at index 0 and growing the queue towards the end of the Array is too inefficient, for the same reason that the Vector approach was inefficient. Instead, we maintain two indexes, the head and tail index and let them “slide” towards the end of the Array and then wrap around. "Fred""Barney""Wilma" "Fred""Barney""Wilma" headtail
©Duane Szafron Sliding Indexes "Fred""Barney""Wilma" headtail add "Fred""Barney""Wilma" headtail "Betty" remove add "Pebbles""Barney""Wilma" headtail "Betty" headtail "Barney""Wilma""Betty"
©Duane Szafron Sliding Indexes 2 remove add remove "Pebbles""Barney""Wilma" headtail "Betty" "Pebbles""Wilma" headtail "Betty" "Pebbles""Wilma" headtail "Betty""Slate" "Pebbles" headtail "Betty""Slate"
©Duane Szafron Array-Based Queues - Empty and Full We leave one empty entry in the Queue. The condition for an empty Queue is: head == tail. The condition for a full Queue is: tail is one “behind” head.
©Duane Szafron Some Principles from the Textbook 13. Understand the complexity of the Structure you use. principles from Bailey ch. 7