In this article, we are going to explore the main concepts behind a linked list. We are going to see how to implement a LinkedList in C# using the LinkedList and LinkedListNode classes and then, how to implement custom linked list classes and methods.

To download the source code for this article, you can visit our GitHub repository.

We have a lot to cover, so let’s start.

What is a Linked List?

A linked list is a data structure to store items in a linear way. It is composed of nodes that connect with the next and previous items.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

A LinkedList C#

The .NET Framework provides us with the LinkedList generic class under the System.Collection.Generic namespace. This class represents a doubly linked list. It means that any node points to a previous and a next node where the previous and/or the next can be null. It is slightly different from the singly linked list, where each node point only to the next node. 

This class implements the ICollection interface, hence, it contains methods like Remove(), Clear(), CopyTo(), and properties such as Count and IsReadOnly.

We already have an article about some common .NET Collections, so you might want to read it if you’re not familiar with these.

As with every linked list, this class works with nodes and .NET has a LinkedListNode generic class to represent it.

LinkedList<T> Constructors

The LinkedList class has three constructors. Let’s check them:

ConstructorDescription
LinkedList()Initializes an empty LinkedList.
LinkedList(IEnumerable)Initializes a LinkedList with the elements of parameter IEnumerable.
LinkedList(SerializationInfo, StreamingContext)Initializes an empty LinkedList with SerializationInfo and StreamingContext instances to
specify how to serialize the LinkedList.

For this article, we are going to initialize an empty LinkedList of int:

var linkedList = new LinkedList<int>();

LinkedList<T> Properties

The .NET LinkedList class has three properties:

PropertyDescription
CountAn integer that represents the number of nodes in the linked list instance.
LastA LinkedListNode that represents the last node within the linked list instance.
FirstA LinkedListNode that represents the first node within the linked list instance.

It is good to mention that when we insert or remove any LinkedListNode<T> from the list, the insertion/removal method updates the Count property.  That said, when we need this information, it is not necessary to loop through the entire list by counting the number of elements.

Also, it is worth mentioning that the First and the Last property always updates when we insert/remove a node at the beginning or at the end of the list.

LinkedList<T> Main Methods

The LinkedList<T> class contains several methods. For this article, we are going to learn how to use the seven main methods from this class.

Add a Value Using the AddFirst() Method

Let’s use the AddFirst() method:

linkedList.AddFirst(1);

This method replaces the linked list’s first position with the new value, making the old first element the second node in the list.

The AddFirst() method provides us with an overload in case we need to insert a LinkedListNode instead of a value. Let’s check how to use this overload:

linkedList.AddFirst(new LinkedListNode<int>(2));

When we call the method passing a value as a parameter, the AddFirst() method returns the LinkedListNode created to insert. On the other hand, when we provide a LinkedListNode instance, it has no return.

Let’s see our list’s elements after these two insertions:

==> 2 ==> 1

Use the Find() Method

Now we have two elements in our linked list, let’s use the Find() method to find any node inside our linked list:

var node = linkedList.Find(2);

This method returns a LinkedListNode with the element we want to retrieve. If the element doesn’t exist in our list, this method returns null.

Insert a Value With the AddAfter() Method

Now that we know how to find any element inside our linked list, let’s add the third element after the value 2, using the AddAfter() method:

var node = linkedList.Find(2);
if (node is not null)
    linkedList.AddAfter(node, 3);

Once we want to add a new element after the value 2, first we need to find the LinkedListNode with this value. Then, after checking if this value is not null, we use the method AddAfter() method passing as a parameter the LinkedListNode we found and the value we want to insert.

Let’s check the results:

2 ==> 3 ==> 1

Add a Value With the AddBefore() Method

Very similar to the AddAfter() method, we have the AddBefore() method. Let’s check it:

var node = linkedList.Find(1);
if (node is not null)
    linkedList.AddBefore(node, 4);

This time, we are going to insert the value 4 before the value 1. To accomplish it, we need to find the value 1, then, use the AddBefore() method to insert the value 4.

==> 2 ==> 3 ==> 4 ==> 1

Add a Value With the AddLast() Method

Let’s add a new element in our linked list’s last position:

linkedList.AddLast(5);

Now, let’s check our list’s elements:

==> 2 ==> 3 ==> 4 ==> 1 ==> 5

Remove Elements From the Linked List

Let’s check how to remove elements from our linked list:

linkedList.Remove(1);

This method is going to remove the first occurrence from the linked list. Once it successfully removes the element from the list, it returns true, otherwise, if the list doesn’t contain the element we want to remove, this method returns false

After removing the element, let’s check the result:

==> 2 ==> 3 ==> 4 ==> 5

Clear the Entire Linked List

Now that we have a linked list full of elements, let’s remove every element from it:

linkedList.Clear();

This method removes all nodes from the linked list. From now, our linked list is empty.

Implement a Custom Linked List in C#

Now that we know how the LinkedList<T> and LinkedListNode<T> classes work in C#, let’s implement our own custom linked list.

We are going to separate it into pieces and implement class by class.

Create the Node<T> Class

Let’s start by creating the Node generic class:

public class Node<T>
{
    public T Value { get; set; }
    public Node<T>? Next { get; set; }
    public Node<T>? Prev { get; set; }

    public Node(T value)
    {
        Value = value;
    }
}

Here we have the Value public property representing the value we want to store within the node. The Next property represents the next node from our linked list and the Prev property represents the previous node.

Note that the Next and Prev property must be nullable, because, in a doubly linked list, the Prev property from the first node and the Next property from the last node points to null.

Custom Linked Class and IEnumerable Interface Members

Now that we have the generic Node class, let’s create the CustomLinkedList class:

public class CustomLinkedList<T> : IEnumerable<Node<T>>
{
    public Node<T>? First { get; set; }
    public int Count { get; set; }
    
    public IEnumerator<Node<T>> GetEnumerator()
    {
        Node<T>? currentNode = First;

        while (currentNode is not null)
        {
            yield return currentNode;
            currentNode = currentNode.Next;
        }
    }

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

Once we are talking about a list, we probably want to use it inside a foreach loop and System.Linq methods. For that, we are going to implement the IEnumerable interface methods.

Also, it is necessary to create at least two properties, a nullable First property representing the first node from the linked list and an integer Count, representing the number of elements within the list.

Next, let’s implement a couple of methods in our CustomLinkedList class.

Implement the AddFirst() Method

Let’s implement a method to add an element to our list first position:

public void AddFirst(Node<T> nodeToAdd)
{
    if (First is null)
    {
        First = nodeToAdd;
    }
    else
    {
        nodeToAdd.Next = First;
        First.Prev = nodeToAdd;

        First = nodeToAdd;
    }

    Count++;
}

This method receives, as a parameter, the node we want to insert into the list. To begin, we need to check if the First property is null. In case it is null, we know that our list is empty, so, the First property becomes the node we want to insert into the list.

In case our list already has elements, first, it is necessary to make the Next property from the node (parameter) point to the first node from our list. Secondly, we need to make the Prev property from the First property point to the node we receive as a parameter. To finish, we need to make our list’s first node becomes the node we receive as a parameter.

Once we are done adding elements to our list, we need to increase the Count property by one.

Create the Find() Method

Now, let’s retrieve an element from the list:

public Node<T>? Find(T valueToFind)
{
    var aux = First;

    while (aux is not null)
    {
        if (EqualityComparer<T>.Default.Equals(aux.Value, valueToFind))
        {
            return aux;
        }

        aux = aux.Next;
    }

    return default;
}

In the first step, we create an auxiliary variable (aux) to represent the list’s first element.

In the second step, we create a while loop to iterate through the list comparing the current element with the value we want to retrieve. Once we find the element with the same value, we return it. In case we don’t find any element with the same value, we return default (null). 

Remove Elements

Now that we know how to find a value from the list, let’s implement a Remove() method:

public void Remove(T valueToRemove)
{
    var find = Find(valueToRemove);

    if (find is null)
    {
        return;
    }

    var next = find.Next;
    var prev = find.Prev;

    if (prev is not null)
    {
        prev.Next = next;
    }

    if (next is not null)
    {
        next.Prev = prev;
    }

    Count--;
}

This method receives, as a parameter, the value we want to remove from the list.

The first step consists of finding the first node with the value within our list. The Find() method may return null, so we need to check if the value we want to remove exists within the list.

As the next step, we are assigning the next and the previous value inside two variables (next, prev).

If the prev variable is null, it means that we are at the list’s first position. That said, we don’t need to do anything with the prev node.

In the same way, if the next variable is null, we are dealing with the list’s last position, so, no action is necessary with the next node.

Once the prev variable is not null, we need to assign the next variable to the prev.Next node. Likewise, we need to assign prev variable to the next.Prev node.

Then, as we removed a node from the list, we need to decrease the Count property by one. 

You can check the full CustomLinkedList implementation here.

Conclusion

In this article, we have learned that a linked list is a data structure to store items in a linear way and the linked list composition.

Then, we learned that .NET Framework provides us with a full linked list implementation with the LinkedList class. We studied the main methods, properties, and constructors.

Additionally, we created our own Node and CustomLinkedList classes and implemented a couple of methods.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!