Circular singly linked list

Circular lists are a type of linked list. They can be singly or doubly linked. Their distinguishing feature is that the last element stores a reference to the first element, creating a closed or circular list.

365

For example, if we have a list consisting of one head element, then we can close such a list as follows:

1
head.next = head;

For implementation, we will take the element class that is used in a singly linked list:

1
2
3
4
5
6
7
8
9
public class Node<T>
{
    public Node(T data)
    {
        Data = data;
    }
    public T Data { get; set; }
    public Node<T> Next { get; set; }
}

Now, let’s define a circular list class:

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System.Collections;
using System.Collections.Generic;
namespace SimpleAlgorithmsApp
{
    public class CircularLinkedList<T> : IEnumerable<T>  // circular linked list
    {
        Node<T> head; // head/first element
        Node<T> tail; // last/tail element
        int count;  //number of elements in the list
        //adding an element
        public void Add(T data)
        {
            Node<T> node = new Node<T>(data);
            // if the list is empty
            if (head == null)
            {
                head = node;
                tail = node;
                tail.Next = head;
            }
            else
            {
                node.Next = head;
                tail.Next = node;
                tail = node;
            }
            count++;
        }
        public bool Remove(T data)
        {
            Node<T> current = head;
            Node<T> previous = null;
            if (IsEmpty) return false;
            do
            {
                if (current.Data.Equals(data))
                {
                    // If the knot is in the middle or at the end
                    if (previous != null)
                    {
                        // we remove the current node, now previous refers not to current, but to current.Next
                        previous.Next = current.Next;
                        // If the node is the last one,
                        // change the variable tail
                        if (current == tail)
                            tail = previous;
                    }
                    else // if the first element is removed
                    {
                        
                        // if there is only one element in the list
                        if(count==1)
                        {
                            head = tail = null;
                        }
                        else
                        {
                            head = current.Next;
                            tail.Next = current.Next;
                        }
                    }
                    count--;
                    return true;
                }
                previous = current;
                current = current.Next;
            } while (current != head);
            return false;
        }
        public int Count { get { return count; } }
        public bool IsEmpty { get { return count == 0; } }
        public void Clear()
        {
            head = null;
            tail = null;
            count = 0;
        }
        public bool Contains(T data)
        {
            Node<T> current = head;
            if (current == null) return false;
            do
            {
                if (current.Data.Equals(data))
                    return true;
                current = current.Next;
            }
            while (current != head);
            return false;
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)this).GetEnumerator();
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            Node<T> current = head;
            do
            {
                if (current != null)
                {
                    yield return current.Data;
                    current = current.Next;
                }
            }
            while (current != head);
        }
    }
}

Here, we’ll also need references to the conditional first and last elements in the form of the variables head and tail, although formally the list will be circular and have no beginning or end. Adding actually amounts to resetting the pointer to the last element, tail, and placing the new element between tail and head:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void Add(T data)
{
    Node<T> node = new Node<T>(data);
    // if the list is empty
    if (head == null)
    {
        head = node;
        tail = node;
        tail.Next = head;
    }
    else
    {
        node.Next = head;
        tail.Next = node;
        tail = node;
    }
    count++;
}

365

When deleting, we reset the pointer to the next element at the previous element in relation to the one being deleted:

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
public bool Remove(T data)
{
    Node<T> current = head;
    Node<T> previous = null;
    if (IsEmpty) return false;
    do
    {
        if (current.Data.Equals(data))
        {
            // If the knot is in the middle or at the end
            if (previous != null)
            {
                // We remove the current node, now previous refers not to current, but to current.Next
                previous.Next = current.Next;
                // If the node is the last one,
                // change the variable tail
                if (current == tail)
                    tail = previous;
            }
            else //if the first element is removed
            {
                // if there is only one element in the list
                if(count==1)
                {
                    head = tail = null;
                }
                else
                {
                    head = current.Next;
                    tail.Next = current.Next;
                }
            }
            count--;
            return true;
        }
        previous = current;
        current = current.Next;
        
    } while (current != head);
    return false;
}

365

Using a ring list:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CircularLinkedList<string> circularList = new CircularLinkedList<string>();
circularList.Add("Tom");
circularList.Add("Bob");
circularList.Add("Alice");
circularList.Add("Jack");
foreach (var item in circularList)
{
    Console.WriteLine(item);
}
circularList.Remove("Bob");
Console.WriteLine("\n After removal: \n");
foreach (var item in circularList)
{
    Console.WriteLine(item);
}

Console output:

Tom
Bob
Alice
Jack

After removal:
Tom
Alice
Jack

Explore More IT Terms


Share this term: Facebook X LinkedIn WhatsApp Email

Leave a Reply

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