Linked Lists

Introduction

A linked list is a collection with the following rules:

Node

Nodes of a Linked List

In reality, there are various types of linked lists. A singly linked list is a one-way directional list where each item points (only) to the item next to it (in a somewhat right direction). The description we just gave is conform to a singly linked list. Another type is the doubly linked list:

Nodes of a Linked List

The last type of linked list is called a circular linked list. This list is primarily created as either a singly linked list or a doubly linked list:

Circular Singly Linked List

Circular Doubly Linked List

Practical LearningPractical Learning: Introducing Geometric Accessories

  1. Start Microsoft Visual Studio
  2. Create a Windows Forms App named Exercise9

Creating a Linked List

Although you can create a linked list collection class from scratch, to assist you, the .NET Framework provides a class named LinkedList and that is a member of the System.Collections.Generic namespace. LinkedList<> is a generic collection class with three constructors. The default constructor allows you to create an empty linked list. Here is an example of using it:

private void Exercise_Load(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();
}

Another constructor allows you to create a linked list using an existing list. Its syntax is:

public LinkedList(IEnumerable<T> collection);

The argument can be a variable from any class that implements the IEnumerable<T> interface. Here is an example of using this second constructor:

private void Exercise_Load(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
}

Fundamental Operations on a Linked List

Introduction to a Node as an Object

As mentioned already, it is a tradition to call an item of a linked list a node. To define a node as a true object, the .NET Framework provides a sealed class named LinkedListNode<>:

public sealed class LinkedListNode<T>

This class has only properties, no methods.

The Number of Nodes of a List

The LinkedList<> class starts as follows:

public class LinkedList<T> : ICollection<T>, 
            		     IEnumerable<T>,
            		     ICollection, IEnumerable,
            		     ISerializable,
            		     IDeserializationCallback

As you can see, the LinkedList<> class implements the ICollection interface. This gives it a Count property that produces the number of nodes. Here is an example of accessing it:

private void Exercise_Load(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);

    MessageBox.Show("There are " + numbers.Count.ToString() + " numbers in the list",
                    "Linked List",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Linked List

Adding a Node

The primary operation to perform on a linked list is to add a new node to it. To support it, the LinkedList<> class is equipped with various methods. One of those methods is named AddLast. It is overloaded with two versions. One of those versions uses the following syntax:

public LinkedListNode<T> AddLast(T value);

This method expects the new value as argument. Here is an example of calling it:

namespace Numerotation
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            LinkedList<double> numbers = new LinkedList<double>();

            numbers.AddLast(148.24);
        }
    }
}

Another version of this method is:

public void AddLast(LinkedListNode<T> node);

This version expects a LinkedListNode<> object as argument. Here is an example of calling it:

private void Exercise_Load(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);

    numbers.AddLast(number);
}

In the same way, you can use this method to add new items. Here are examples:

private void Exercise_Load(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();

    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddLast(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number);

    number = new LinkedListNode<double>(4.19);
    numbers.AddLast(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddLast(number);
}

Looking for a Node

Introduction

Because the LinkedList<> class implements the ICollection interface, it inherits the Contains() method. As a reminder, its syntax is:

public bool Contains(T value);

This method checks whether the linked list contains a node that has the value passed as argument. If that node is found, the method returns true. Otherwise it returns false. Here is an example of calling it:

private void Exercise_Load(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddFirst(number);

    if( numbers.Contains(2222.06) == true )
        MessageBox.Show("The list contains 2222.06.",
                        "Linked List",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
    else
        MessageBox.Show("There is no such a number in the list.",
                        "Linked List",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);

This method works only if the type of the node is able to perform the comparison for equality. If you are using values of primitive types (int, char, double, DateOnly, TimeOnly, DateTime, etc) or string, the method would work fine. If you are using your own class, make sure you override the Equals() method in it.

Finding a Node

While the Contains() method is used to look for a value in a linked list, it only lets you know whether the value was found. To let you get the actual node that has that value, the LinkedList<> class is equipped with a method named Find. Its syntax is:

public LinkedListNode<T> Find(T value);

When this method is called, the compiler starts looking for the value in the linked list. If it finds it, the method returns its node. If there is more than one node with that value, the method returns only the first node that has that value. Here is an example of calling this method:

private void Exercise_Load(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddFirst(number);

    numbers.AddFirst(2747.06);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddFirst(number);

    if( numbers.Find(2747.06) != null )
        MessageBox.Show("2747.06 was found in the list.",
                    "Linked List",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
    else
        MessageBox.Show("2747.06 is nowhere in the list.",
                    "Linked List",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Linked List

If the list contains more than one node that has the value but you prefer to use the last node, the LinkedList<T> class is equipped with a method named FindLast(). Its syntax is:

public LinkedListNode<T> FindLast(T value);

Once again, remember that these two methods are ready to work on primitive types. If you are using your own class for the type of node, you should (must) override the Equals() method.

Getting Each Node

As you can see, the LinkedList<T> class doesn't implement the IList<> interface, which means it doesn't have an Item property. As we have seen with the AddLast() method and as we will see in the next sections, each method used to add a node is provided in two versions. One of the versions returns a LinkedListNode<> object. This means that, when performing an addition operation, you can get the returned value and do what you want with it.

The LinkedList<T> class implements the IEnumerable<> interface. This makes it possible to use foreach to access each node. This can be done as follows:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();
        
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    
    numbers.AddFirst(number);

    foreach (double nbr in numbers)
        MessageBox.Show(nbr.ToString());
}

Navigating Among the Nodes

The First and the Last Nodes

As mentioned already, a linked list has a first and a last nodes (some people or documentations call them the head and the tail). To identify the first node, the LinkedList<> class is equippped with a read-only property named First:

public LinkedListNode<T> First { get; }

The last node is represented by a read-only property of the same name and that, too, is a LinkedListNode<> object:

public LinkedListNode<T> Last { get; }

Here are examples of accessing these properties:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    LinkedList<double> numbers = new LinkedList<double>();

    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(2222.06);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddFirst(number);

    MessageBox.Show("The value of the first node is " + numbers.First.Value);
    MessageBox.Show("The value of the last node is " + numbers.Last.Value);
}

The Next and Previous Nodes

To access a node that is next to an existing node, you must first know what node is used as reference. To let you access the next node, the LinkedListNode<> class is equipped with a read-only property named Next:

public LinkedListNode<T> Next { get; }

To let you access the node previous to an existing one, the LinkedListNode<> class is equipped with the read-only property named Previous:

public LinkedListNode<T> Previous { get; }

Remember that in both cases, you need a node as reference.

Creating Nodes

Adding the First Node

When dealing with a linked list, you have many options on how to add a new node. As mentioned already, a linked list has a first node, a last node, and one or more nodes between them. All nodes have and use some references with regards to the node(s) close to them. Based on this, when adding a new node, you have to specify whether you want it as the first node, the last node, the node before a certain node, or the node after a certain one. The LinkedList class easily supports all these operations with very little effort on your part.

We saw that you could call the AddFirst() method to add a new node. In reality, there is no such a thing as simply adding a new node to a linked list. When a linked list has just been created and it is empty, it holds a reference to a null node. There is nothing you can do with that node and you don't need to do anything with it. To start adding nodes, you have the option of setting it as the first or the last item. This would not make any difference because there is no other node in the list.

After adding a node, it becomes a reference that new nodes can use. If you call the AddFirst() method, the new node would be added before any existing node in the collection.

Adding the Last Node

By contrast to adding a first node, you can call a method named AddLast. It is overloaded with versions whose syntaxes are:

public LinkedListNode<T> AddLast(T value);
public void AddLast(LinkedListNode<T> node);

When you call this method, the value or node you pass will be added as the last item in the list. Here is an example:

namespace Numbers
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnLinkedList_Click(object sender, EventArgs e)
        {
            List<double> values = new List<double>();

            values.Add(84.597);
            values.Add(6.47);
            values.Add(2747.06);
            values.Add(282.924);

            LinkedList<double> numbers = new LinkedList<double>(values);
            LinkedListNode<double> number = new LinkedListNode<double>(148.24);
            numbers.AddFirst(number);

            number = new LinkedListNode<double>(35.75);
            numbers.AddFirst(number);

            numbers.AddLast(2747.06);

            number = new LinkedListNode<double>(2222.06);
            numbers.AddFirst(number);

            number = new LinkedListNode<double>(4.19);
            numbers.AddFirst(number);

            number = new LinkedListNode<double>(66.18);
            numbers.AddFirst(number);

            foreach (double dbl in numbers)
                lbxLinkedList.Items.Add(dbl);
        }
    }
}

Linked List

Nodes Maintenance in a Linked List

Inserting a Node Before a Referenced One

A linked list supports the concept of inserting a node but not exactly like traditional collections do it. With a linked list, you must add a node before or after an existing node used as reference.

Behind the scenes, before inserting a node, you must identify the position where you want to put it. That is, you must identify what node you will use as reference:

Inserting a New node Before a Node

In this case, you want to insert a new node before the Other Node. Behind the scenes, the reference between the two existing nodes must be brocken. Then the new node points to the Other Node as its next and the Other Node points at the New Node as its previous:

Inserting a New node Before a Node

After the new node has been added, it must point to the previous node (Some Node in our example) as its previous item. The previous node (Some Node in our example) must now point to the new node as its next item:

Inserting a New node Before a Node

As you may imagine, to insert a node, you must provide two pieces of information: a reference to the node that will succeed the new node, and the new node (or its value). If the referenced node is the first item of the list, the new node would become the new first object.

To assist you with this operation, the LinkedList class provides a method named AddBefore. This method is overloaded with two versions whose syntaxes are:

public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode);
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value);

In both cases, you pass a first argument as an existing node. In the first case, you must pass the LinkedListNode<> object that will be inserted the node. Here is an example:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number);

    numbers.AddLast(2747.06);

    LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number222206);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddBefore(number222206, number);

    number = new LinkedListNode<double>(275.775);
    numbers.AddLast(number);

    foreach (double dbl in numbers)
        lbxLinkedList.Items.Add(dbl);
}

Linked List

In the second version, you directly pass the value to be positioned before node.

Inserting a Node After a Referenced One

Instead of inserting a node before an existing one, you can add it after one. The approach is logically the same as inserting a node before another, except that the sequence is reversed. First identify the node that will be used as reference. Start the process to add the new node after that one. Behind the scenes, the referenced node will point to the new node as its next and the new node will point to the existing node as its previous:

Inserting a New node After an Existing Node

After the new node has been added, it will point to the node after it as its next. The other node will point to the new node as its previous:

Inserting a New node After an Existing Node

If the new node is added after the last node, the new node will become the new last node.

To let you insert a node after an existing node, the LinkedList<> class is equipped with a method named AddAfter. It comes in two versions and their syntaxes are:

public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode);
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value);

The arguments follow the same description as the AddBefore() method, only in reverse. Here is an example:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    LinkedListNode<double> number3575 = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number3575);

    numbers.AddLast(2747.06);

    LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number222206);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddBefore(number222206, number);

    number = new LinkedListNode<double>(275.775);
    numbers.AddAfter(number3575, number);

    foreach (double dbl in numbers)
        lbxLinkedList.Items.Add(dbl);
}

Linked List

The Value of a Node

Probably the most important aspect of a node is its value. To support it, the LinkedListNode<> class has a property named Value:

public T Value { get; set; }

Because this is a read-write property, you can use its write-accessory to specify or change its value. On the other hand, you can access the value of a node using this property.

Deleting Nodes

Deleting the First or Last Node

When it comes time to delete a node, you have many options, such as deleting the first or the last node of the list. To let you delete the first node, the LinkedList<> class is equipped with a method named RemoveFirst. Its syntax is:

public void RemoveFirst();

As you can see, this method takes no argument. When it is called:

To let you delete the last node, the LinkedList<> class is equipped with a method named RemoveLast. Its syntax is:

public void RemoveLast();

This method follows the same logic as the RemoveFirst() method, only in reverse. Here are examples of calling these methods:

namespace Numbers
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void btnLinkedList_Click(object sender, EventArgs e)
        {
            List<double> values = new List<double>();
            values.Add(84.597);
            values.Add(6.47);
            values.Add(2747.06);
            values.Add(282.924);

            LinkedList<double> numbers = new LinkedList<double>(values);
            LinkedListNode<double> number = new LinkedListNode<double>(148.24);
            numbers.AddFirst(number);

            LinkedListNode<double> number3575 = new LinkedListNode<double>(35.75);
            numbers.AddFirst(number3575);

            numbers.AddLast(2747.06);

            LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
            numbers.AddLast(number222206);

            number = new LinkedListNode<double>(4.19);
            numbers.AddFirst(number);

            number = new LinkedListNode<double>(66.18);
            numbers.AddBefore(number222206, number);

            number = new LinkedListNode<double>(275.775);
            numbers.AddAfter(number3575, number);

            foreach (double dbl in numbers)
                lbxOriginalList.Items.Add(dbl);

            numbers.RemoveFirst();
            numbers.RemoveLast();

            foreach (double dbl in numbers)
                lbxOtherList.Items.Add(dbl);
        }
    }
}

Linked List

Removing a Node by Value

There are two ways you can delete an item of a collection. As one way to do this, the LinkedList<> class is equipped with a method named Remove. It comes in two versions. If you know the exact value of the item you want to remove, you can call the following version of that method:

public bool Remove(T value);

When calling this method, pass the value to delete. The compiler would first look for a node that has that value:

An alternative is to delete a node based on its reference. To do this, use the following version:

public void Remove(LinkedListNode<T> node);

When calling this method, pass a reference to the node you want to delete. Here is an example:

private void btnLinkedListClicked(object sender, EventArgs e)
{
    List<double> values = new List<double>();
    values.Add(84.597);
    values.Add(6.47);
    values.Add(2747.06);
    values.Add(282.924);

    LinkedList<double> numbers = new LinkedList<double>(values);
    LinkedListNode<double> number = new LinkedListNode<double>(148.24);
    numbers.AddFirst(number);

    LinkedListNode<double> number3575 = new LinkedListNode<double>(35.75);
    numbers.AddFirst(number3575);

    numbers.AddLast(2747.06);

    LinkedListNode<double> number222206 = new LinkedListNode<double>(2222.06);
    numbers.AddLast(number222206);

    number = new LinkedListNode<double>(4.19);
    numbers.AddFirst(number);

    number = new LinkedListNode<double>(66.18);
    numbers.AddBefore(number222206, number);

    LinkedListNode<double> number275775 = new LinkedListNode<double>(275.775);
    numbers.AddAfter(number3575, number275775);

    foreach (double dbl in numbers)
        lbxLinkedListOriginal.Items.Add(dbl);

    numbers.Remove(number275775);

    foreach (double dbl in numbers)
        lbxLinkedListOther.Items.Add(dbl);
}

Linked List

Clearing a Linked List

Clearing a list consists of deleting all of its items. To do this, you could continuously call one of the versions of the Remove() method. As a faster solution, the LinkedList<> class is equipped with a method named Clear. Its syntax is:

public void Clear();

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2014-2023, FunctionX Monday 06 December 2021 Next