## Learning Outcomes

At the end of this lecture, you’ll be able to:

- Explain and trace the
**core operations of Queue**(enqueue, dequeue, front, empty). - Describe the difference between
`enqueue`

and`dequeue`

. - Implement the core operations of Queue efficiently (array based and linked base).
- Explain why an efficient linked implementation of Queue requires a
**tail**pointer. - Explain why an efficient array based implementation of Queue can logically be viewed as a
**circular data structure**. - Define
*Steque*,*Quack*, and**Deque**ADT.

## Lecture Plan

In this lecture, we'll cover the following lessons:

- Queue Abstract Data Type
- Queue Interface
- Linked Implementation of Queue⚡
- Trace Linked Implementation⚡
- LinkedQueue⚡
- Array Implementation of Queue⚡
- Trace Array Implementation⚡
- ArrayQueue⚡
- Restricted Data Structures: Mixing it up!⚡

Lessons marked with ⚡ contain exercise/activity.

## Downloads

## Queue Abstract Data Type ↗

A **queue** ADT supports two main operations:

**enqueue**which adds an element to the data structure**dequeue**which removes__the least recently added element__that was not yet removed

The order in which elements are removed gives rise to the term **FIFO** (first in, first out) to describe a queue.

It helps to visualize a queue as an ADT where elements are removed from the front but added to the back, analogously to when people line up to wait for goods or services.

A queue has a variety of applications such as:

- Serving requests on a shared resource, like a printer, CPU, etc.
- Any application that follows a “first come, first served” policy, e.g. customer-service, call-center/ticketing system, etc.
- Whenever it is necessary to preserve sequencing order

## Resources

- Wikipedia entry on Queue
- HAckerRank YouTube video on Stack & Queue
- VisuAlgo visualization and interactive demo of lists

## Queue Interface ↗

Here is the `Queue`

interface which we use in this course:

```
/**
* Queue ADT.
*
* @param <T> base type.
*/
public interface Queue<T> {
/**
* Adds a new element to the back of this queue.
*
* @param value to be added
*/
void enqueue(T value);
/**
* Removes the element at the front of this queue.
*
* @throws EmptyException when empty() == true.
*/
void dequeue() throws EmptyException;
/**
* Peeks at the front value without removing it.
*
* @return the value at the front of this queue.
* @throws EmptyException when empty() == true.
*/
T front() throws EmptyException;
/**
* Checks if empty.
*
* @return true if this queue is empty and false otherwise.
*/
boolean empty();
}
```

Make note of `enqueue`

and `dequeue`

: one adds the other removes. Also, there is a `front`

which allows you to peek at the front of the queue without removing the front element.

## Linked Implementation of Queue ↗

A singly linked list can be used to implement the Queue ADT efficiently as long as it has a `tail`

pointer (as well as the `head`

pointer). The `tail`

pointer is a reference variable pointing to the other end (opposite of `head`

) of the queue.

Exercise Think about how to implement a queue using a singly linked list such that the core operations are **constant time**.

Operation | How? | Time |
---|---|---|

`enqueue` | $O(1)$ | |

`dequeue` | $O(1)$ | |

`front` | $O(1)$ | |

`empty` | $O(1)$ |

## Solution

The front of the queue would be the HEAD node of the singly linked list. The back of the queue would be the TAIL node of the singly linked list. Every time we want to `enqueue`

an additional value to the queue, we would create a new node and set it as the new TAIL node. Then when we want to `dequeue`

a value from the front of the queue, we set the HEAD to the current HEAD node’s `.next`

. As such, the HEAD node will always be at the front of the queue, and calling `front`

would return the value of the HEAD node.

Operation | How? | Time |
---|---|---|

`enqueue` | prepend the list and update the `tail` | $O(1)$ |

`dequeue` | delete from front: `head = head.next` | $O(1)$ |

`front` | return `head.data` | $O(1)$ |

`empty` | check if `head` is `null` | $O(1)$ |

## Trace Linked Implementation ↗

Think about a linked implementation of queue such that the core operations are **constant time**.

Exercise Complete the table below: update the linked list as you trace the operations; show value returned if any.

Operation | Linked List | Value Returned |
---|---|---|

`enqueue(1)` | `HEAD -> (1) <- TAIL` | |

`enqueue(2)` | `HEAD -> (1) -> (2) <- TAIL` | |

`enqueue(3)` | ||

`dequeue()` | ||

`enqueue(4)` | ||

`dequeue()` | ||

`enqueue(5)` | ||

`front()` | ||

`dequeue()` | ||

`front()` |

## Solution

Operation | Linked List | Value Returned |
---|---|---|

`enqueue(1)` | `HEAD -> (1) <- TAIL` | |

`enqueue(2)` | `HEAD -> (1) -> (2) <- TAIL` | |

`enqueue(3)` | `HEAD -> (1) -> (2) -> (3) <- TAIL` | |

`dequeue()` | `HEAD -> (2) -> (3) <- TAIL` | |

`enqueue(4)` | `HEAD -> (2) -> (3) -> (4) <- TAIL` | |

`dequeue()` | `HEAD -> (3) -> (4) <- TAIL` | |

`enqueue(5)` | `HEAD -> (3) -> (4) -> (5) <- TAIL` | |

`front()` | `HEAD -> (3) -> (4) -> (5) <- TAIL` | 3 |

`dequeue()` | `HEAD -> (4) -> (5) <- TAIL` | |

`front()` | `HEAD -> (4) -> (5) <- TAIL` | 4 |

## Resources

- USFCA interactive demo of Queue (Linked List Implementation)

## LinkedQueue ↗

Exercise Open the starter code and complete the implementation of `LinkedQueue`

. (Do this at home!)

## Solution

Please check the posted solution.

## Array Implementation of Queue ↗

We want to implement the `Queue`

interface using an array as an internal data storage.

Exercise Think about how to implement a queue using an array such that the core operations are **constant time**. Assume the array is sufficiently large.

Operation | How? | Time |
---|---|---|

`enqueue` | $O(1)$ | |

`dequeue` | $O(1)$ | |

`front` | $O(1)$ | |

`empty` | $O(1)$ |

## Solution

Initialize two variables `front`

and `back`

to zero. When you `equeue`

, add to the back. Use the `back`

variable to index into the array. Then increment it. When you are asked for front element, simply return `arr[front]`

. When you dequeue, simply increment `front`

.

Since you remove from the “front” of the array, then there will be empty positions at the front. So, when the `back`

variable reached the end of the array, it can **wrap around it** and write to the (actual) “front” of the array, to positions that were removed earlier.

This gives rise to a **logical view** of array being a circular data structure.

You can also dynamically grow the array when `back`

reaches `front`

.

Operation | How? | Time |
---|---|---|

`enqueue` | `data[back] = value` and `back = ++back % length` | $O(1)$ |

`dequeue` | `front = ++front % length` | $O(1)$ |

`front` | return `arr[front]` | $O(1)$ |

`empty` | check if `numElement == 0` | $O(1)$ |

The `% length`

is a trick we use to reset the index when it reaches the length of the array. We could rewrite it as

```
font = front + 1;
if (front == length) {
front = 0;
}
```

The example above replaces `front = ++front % length`

. The same idea can be applied to updating `back`

variable.

## Resources

- Data structures: Array implementation of Queue on YouTube.
- Using an Array to represent a Circular Queue on YouTube.

## Trace Array Implementation ↗

Think about an array based implementation of queue such that the core operations are **constant time**.

Exercise Complete the table below: update the array values at indices `0`

, `1`

, `2`

, `3`

, and `4`

as you trace the operations; show value returned if any.

Operation | [ 0 ] | [ 1 ] | [ 2 ] | [ 3 ] | [ 4 ] | Return Value |
---|---|---|---|---|---|---|

`enqueue(1)` | ||||||

`enqueue(2)` | ||||||

`enqueue(3)` | ||||||

`dequeue()` | ||||||

`enqueue(4)` | ||||||

`dequeue()` | ||||||

`enqueue(5)` | ||||||

`front()` | ||||||

`dequeue()` | ||||||

`front()` |

## Solution

Operation | [ 0 ] | [ 1 ] | [ 2 ] | [ 3 ] | [ 4 ] | Return Value |
---|---|---|---|---|---|---|

`enqueue(1)` | 1 | |||||

`enqueue(2)` | 1 | 2 | ||||

`enqueue(3)` | 1 | 2 | 3 | |||

`dequeue()` | 2 | 3 | ||||

`enqueue(4)` | 2 | 3 | 4 | |||

`dequeue()` | 3 | 4 | ||||

`enqueue(5)` | 3 | 4 | 5 | |||

`front()` | 3 | 4 | 5 | 3 | ||

`dequeue()` | 4 | 5 | ||||

`front()` | 4 | 5 | 4 |

## Resources

- USFCA interactive demo of Stack (Array Implementation)

## ArrayQueue ↗

Exercise Open the starter code and complete the implementation of `ArrayQueue`

.

Notice the constructor of `ArrayQueue`

does not take in a parameter for the size of the array. Feel free to initialize an array with an arbitrarily chosen capacity.

## Solution

Please check the posted solution.

## Restricted Data Structures: Mixing it up! ↗

We can mix and match the operations of Stack and Queue to build up new data structures! Here are a few that you may come by in various references.

## Steque ADT

A stack-ended queue or *steque* is a data structure that supports `push`

, `pop`

, and `enqueue`

. Here is an example interface:

```
// A stack-ended queue.
public interface Steque<T> {
// is empty?
boolean empty();
// adds a new element to top of Steque.
void push(T value);
// removes and returns top element.
T pop() throws EmptyException;
// adds a new element to bottom of Steque.
void enqueue(T value);
}
```

So, you add from both ends but remove from one end. To better understand this ADT, consider the following sequence of operations and the schematic representation of steque after each operation (top of the steque is to the left):

```
steque.push(1); // [1]
steque.push(2); // [2, 1]
steque.enqueue(3); // [2, 1, 3]
steque.enqueue(4); // [2, 1, 3, 4]
steque.pop(); // [1, 3, 4]
```

## Quack ADT

A queue-ended stack or *quack* is a data structure that supports `push`

, `pop`

, and `dequeue`

. Here is an example interface:

```
// A queue-ended stack.
public interface Quack<T> {
// is empty?
boolean empty();
// adds a new element to the top of Quack.
void push(T value);
// removes and returns top element.
T pop() throws EmptyException;
// removes and returns bottom element.
T dequeue() throws EmptyException;;
}
```

So, you add from one end but remove from both ends. To better understand this ADT, consider the following sequence of operations and the schematic representation of quack after each operation (top of the quack is to the left):

```
quack.push(1); // [1]
quack.push(2); // [2, 1]
quack.push(3); // [3, 2, 1]
quack.push(4); // [4, 3, 2, 1]
quack.pop(); // [3, 2, 1]
quack.dequeue(); // [3, 2]
```

## Deque ADT

Double Ended Queue (Deque) is a limited access data structure that allow insertion/removal at either end in $O(1)$.

- Deque is a stack if you always add/remove at one end.
- Deque is a queue if you always add to one end and remove from other.

Here is an example interface:

```
// A double-ended queue.
public interface Deque<T> {
boolean empty();
T front() throws EmptyException;
T back() throws EmptyException;
void insertFront(T t);
void insertBack(T t);
void removeFront() throws EmptyException;
void removeBack() throws EmptyException;
}
```

The data structures above are not as widely uses as Stack and Queue (especially the first two). We leave it to you as an (unsolved) exercise to implement their operations.