Queues Lab
Set up
Follow the steps from the Scavenger Hunt to mount the COURSES drive. Make a folder QueuesLab in your STUWORK/username folder and open it in VSCode for today’s labwork.
Implementing a circular queue
- 
    
Copy this interface for a Queue into a file
QueueInt.kt:interface Queue<T> { fun isEmpty(): Boolean fun enqueue(item: T) fun dequeue(): T? override fun toString(): String } - 
    
Create a new file
CircularQ.ktand create a classCircularQueue<T>that implements theQueue<T>interface (remember to start with just “stubs” of methods that don’t do anything but return the right thing so that you can compile and test as you go.) Don’t jump into implementing all the methods yet! - Create the following instance variables:
    
itemsthat is aMutableList<T>to hold your datafrontthat starts with -1rearthat also starts with -1 (make sure you understand why that is a good value to start with)
 - 
    
enqueuehas quite a few cases that you need to consider, so start with just implementing the situation where the queue is empty and you are adding the first item. - 
    
Make sure that your code compiles with the following test code:
fun main() { val q = CircularQueue<Int>() q.enqueue(1) } - 
    
Implement a preliminary version of
toStringthat ignores the fact thatfrontcould move and then use that to make sure that your queue has “1” in it. - Circular queues need to grow carefully to keep their items in the right locations relative to each other. Implement the case for 
enqueuewhen the queue is full, keeping the following in mind:- How do you know the queue is full based on the values of 
frontandrear? - If 
frontis 0, you can just calladdnormally - If 
frontisn’t 0, you need to grab the items fromitemsin two sections, one fromfrontto the end ofitemsand another from0torear, usingsubList - You can append another list with 
addAll - Make sure to test your code by adding some more 
enqueuelines to yourmain 
 - How do you know the queue is full based on the values of 
 - 
    
Now is a good time to also implement the case when there is room in the queue and it wasn’t empty.
 - 
    
It’s time to implement
dequeue. Be sure to consider the case where you are removing the last item from the queue and when the queue is already empty. - 
    
Once you start dequeuing, you need your
toStringto take that into account. Update yourtoStringto handle the case wherefrontisn’t 0 and make sure yourdequeueis working correctly. - 
    
There is one more case for
enqueuethat you need to consider. Implement the case where the queue has become empty butitems.sizeisn’t 0. - 
    
Make sure that your code correctly works for these tests:
fun main() { val q = CircularQueue<Int>() q.enqueue(1) q.enqueue(2) q.dequeue() q.enqueue(3) q.enqueue(4) q.enqueue(5) println(q) q.dequeue() println(q) q.dequeue() q.dequeue() q.dequeue() q.enqueue(6) println(q) } 
Implementing a linked queue
- 
    
Create a new file
LinkedQ.ktand implement theQueue<T>interface withLinkedQueue<T>. Note that you can and should add a variablerearthat tracks the end of the linked list for dequeuing. You’ll want to use theNode<T>data class from before:private data class Node<T>( var item: T, var next: Node<T>?) - 
    
Test your code with the same tests as the circular queue:
fun main() { val q = LinkedQueue<Int>() q.enqueue(1) q.enqueue(2) q.dequeue() q.enqueue(3) q.enqueue(4) q.enqueue(5) println(q) q.dequeue() println(q) q.dequeue() q.dequeue() q.dequeue() q.enqueue(6) println(q) } 
Extra
Submit your queue implementations to Moodle for an engagement credit and then try out implementing the following for both of your classes:
peek()clear()size()
How does the time complexity for each implementation compare for these methods? How would any of them be impacted if your reversed the front and rear of your queues?