Queue

A queue is a data structure that operates on the FIFO (First In First Out) principle. When a new element is added, it is placed at the end of the queue, or its tail, and when removed, it is placed at the beginning of the queue, or its head.

A common example of a queue is a typical hospital queue, where new patients stand at the end of the queue, and new patients are admitted from the beginning of the queue.

To implement the queue, we will again use an element class that contains the data itself and a reference to the next element:

1
2
3
4
5
6
7
8
9
public class Node<T>
{
// 1. Made the constructor data parameter nullable to match the property if T can be null
public Node(T data)
{
Data = data;
Next = null; // 2. Explicitly initializing Next to null for clarity
}

public T Data { get; set; }

// 3. Marked Next as nullable (Node<T>?) to explicitly show it can be null at the end of the list
public Node<T>? Next { get; set; }
}

The queue class itself will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;
using System.Collections;
using System.Collections.Generic;

namespace SimpleAlgorithmsApp
{
public class Queue<T> : IEnumerable<T>
{
private Node<T>? head;
private Node<T>? tail;
private int count;

public void Enqueue(T data)
{
Node<T> node = new Node<T>(data);
Node<T>? tempNode = tail;
tail = node;

if (count == 0)
{
head = tail;
}
else
{
if (tempNode != null)
{
tempNode.Next = tail;
}
}
count++;
}

public T Dequeue()
{
if (count == 0 || head == null)
throw new InvalidOperationException(“Queue is empty.”);

T output = head.Data;
head = head.Next;
count–;

if (count == 0)
{
tail = null;
}

return output;
}

public T First
{
get
{
if (IsEmpty || head == null)
throw new InvalidOperationException(“Queue is empty.”);
return head.Data;
}
}

public T Last
{
get
{
if (IsEmpty || tail == null)
throw new InvalidOperationException(“Queue is empty.”);
return tail.Data;
}
}

public int Count => count;
public bool IsEmpty => count == 0;

public void Clear()
{
head = null;
tail = null;
count = 0;
}

// FIXED: Replaced manual null checks with type-safe EqualityComparer
public bool Contains(T data)
{
Node<T>? current = head;
EqualityComparer<T> comparer = EqualityComparer<T>.Default;

while (current != null)
{
if (comparer.Equals(current.Data, data))
return true;

current = current.Next;
}
return false;
}

IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}

public IEnumerator<T> GetEnumerator()
{
Node<T>? current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
}

To add to the queue, we need to reset the reference to the last element tail:

1
2
3
4
5
6
7
8
9
10
11
public void Enqueue(T data)
{
Node<T> node = new Node<T>(data);

if (head == null)
{
// If the queue is empty, the new node is both the head and the tail
head = node;
tail = node;
}
else
{
// If the queue has items, link the current tail to the new node,
// then update the tail pointer.
tail!.Next = node;
tail = node;
}

count++;
}

When deleting, the reference to the first element must be reset. Since the first element is deleted, the next element becomes the new first element:

1
2
3
4
5
6
7
8
9
public T Dequeue()
{
// 1. Better practice to check if the head itself is null alongside the count
if (count == 0 || head == null)
throw new InvalidOperationException(“Queue is empty.”);

T output = head.Data;
head = head.Next;
count–;

// FIXED: Prevent state desynchronization / memory leak
if (count == 0)
{
tail = null;
}

return output;
}

The complexity of the algorithms for adding and removing from the queue is O(1).

 

365

Using the queue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Queue<string> queue = new Queue<string>();
queue.Enqueue(“Kate”);
queue.Enqueue(“Sam”);
queue.Enqueue(“Alice”);
queue.Enqueue(“Tom”);

foreach (string item in queue)
Console.WriteLine(item);
Console.WriteLine();

string firstItem = queue.Dequeue();
Console.WriteLine($”Retrieved item: {firstItem}”);
Console.WriteLine();

foreach (string item in queue)
Console.WriteLine(item);

Console output:

Kate
Sam
Alice
Tom

Extracted item: Kate

Sam
Alice
Tom

Explore More IT Terms


Share this term: Facebook X LinkedIn WhatsApp Email
CONTINUE LEARNING Next: Deque →

Leave a Reply

Your email address will not be published. Required fields are marked *