Data Structures

Singly Linked List Implementation in C++

A singly linked list is the simplest form of a Linked List. The nodes are represented in non-contiguous memory and each maintains the link to the next node. The following are the properties of the linked list.

  • Linked List is dynamic in size and suitable for growing data needs.
  • Ease of insertion and deletion at random positions. Hence the insertion and deletion work faster in Linked List compared to Array.
  • Random access is not possible. Instead, a sequential traversal is required.
  • Unlike arrays, additional memory is required to store the pointers.
  • No cache-friendly for the CPU due to its non-contiguous memory.

1. Singly Linked List Representation

Singly Linked List Representation
Singly Linked List Representation
  • Head: The starting point of the linked list
  • Node: A node consists of the data element and the pointer to the Next node
  • Element: The actual data (provided as 10, 20, and 30)
  • Next: Pointer to the next node

2. Implementation of Singly Linked List in C++

/**
 * C++ example to demonstrate the Singly Linked List
 */
#include <iostream>
using namespace std;

// Linked list node representation
struct Node
{
    int element;
    Node* next;
};

/**
 * Linked list implementation
 */
class List
{
    // Head of the list
    Node* head;

public:
    // Constructor
    List() : head(NULL) {}

    // Insert an element in front of the list
    // Returns the new node inserted
    Node* insert_front(int element);

    // Insert an element after the given node
    // Returns the new node inserted
    Node* insert_after(Node* prev, int element);

    // Delete the front element
    // Returns the next node if available, NULL otherwise.
    Node* delete_front();

    // Delete the element after the given node
    // Returns the next node if available, NULL otherwise.
    Node* delete_after(Node* prev);

    // Search and delete the given element
    void remove(int element);
    
    // Search an element from the list
    // Returns the matching node if found, NULL otherwise.
    Node* search(int element);

    // Traverse the elements
    void traverse(const std::string& msg);
};

Node* List::insert_front(int element)
{
    // Step 1. Create the new node
    Node* new_node = new Node();
    new_node->element = element;

    // Step 2. Link before the head node
    new_node->next = head;

    // Step 3. Change the head to point the new node
    head = new_node;

    return new_node;
}

Node* List::insert_after(Node* prev, int element)
{
    // Step 1. Create the new node
    Node *new_node = new Node();
    new_node->element = element;

    // Step 2. Link the new node after the given node
    new_node->next = prev->next;
    prev->next = new_node;

    return new_node;
}

Node* List::delete_front()
{
    // Step 1. Check if the list is empty and return if true.
    if (head == NULL) {
        return NULL;
    }

    // Step 2. Store the reference to front node as target node and
    // move the head to next node if available or NULL.
    Node* target = head;
    head = head->next;

    // Step 3. Delete the target node
    delete target;

    return head;
}

Node* List::delete_after(Node* prev)
{
    // Step 1. Store the reference to target node
    Node* target = prev->next;

    // Step 2. Check if the target node is NULL and return if true
    if (target == NULL) {
        return NULL;
    }

    // Step 3. Disconnect the target node by linking its previous and next
    // node directly
    prev->next = target->next;

    // Step 4. Delete the target node
    delete target;

    return prev->next;
}

void List::remove(int element)
{
    // Step 1. Check if the list is empty and return if true.
    if (head == NULL) {
        return;
    }
    
    // Step 2. Check if the front node matches the element. If true,
    // invoke the delete_front() operation and return.
    if (head->element == element) {
        delete_front();
        return;
    }
        
    // Step 3. Otherwise, iterate the linked list from start to end,
    // and search the element.
    for (Node* node = head ; node->next != NULL ; node = node->next) {
        
        if (node->next->element == element) {
            // Step 4. If found, set the node as target node and disconnect
            // it by directly linking the previous and next node.
            Node* target = node->next;
            node->next = node->next->next;
            
            // Step 5. Delete the target node
            delete target;
            return;
        }
    }
    
    return;
}

Node* List::search(int element)
{
    // Step 1. Iterate the linked list from start to end
    for (Node* node = head ; node != NULL ; node = node->next) {
        // Step 2. Check if the element matches, and return the node if found.
        if (node->element == element) {
            return node; // Found element
        }
    }
    // Step 3. Return NULL if none matches.
    return NULL; // Not found
}

void List::traverse(const std::string& msg)
{
    cout << msg << endl;
    cout << "HEAD ==> ";
    // Iterate the linked list from start to end
    for (Node* node = head ; node != NULL ; node = node->next) {
        cout << node->element << " ==> ";
    }
    cout << "NULL" << endl << endl;
}

int main()
{
    // Create a linked list
    List list;
    list.traverse("initial list");

    // Insert elements
    list.insert_front(20);
    list.traverse("insert_front(20)");

    Node *node_10 = list.insert_front(10);
    list.traverse("insert_front(10)");
    
    list.insert_after(node_10, 15);
    list.traverse("insert_after(node_10, 15)");

    // Search an element
    Node *node_15 = list.search(15);
    cout << "search(15) matches node " << node_15->element << endl << endl;

    // Delete elements
    list.delete_front();
    list.traverse("delete_front()");
    
    list.delete_after(node_15);
    list.traverse("delete_after(node_15)");
    
    list.remove(15);
    list.traverse("remove(15)");
}
Output
initial list
HEAD ==> NULL

insert_front(20)
HEAD ==> 20 ==> NULL

insert_front(10)
HEAD ==> 10 ==> 20 ==> NULL

insert_after(node_10, 15)
HEAD ==> 10 ==> 15 ==> 20 ==> NULL

search(15) matches node 15

delete_front()
HEAD ==> 15 ==> 20 ==> NULL

delete_after(node_15)
HEAD ==> 15 ==> NULL

remove(15)
HEAD ==> NULL

3. Operations of Singly Linked List

3.1. Insert Front

Connect the new Node before the front Node and update the Head to point to the new Node.

Algorithm

  1. Create the new node.
  2. Link before the Head node.
  3. Finally, change the Head to point to the new node.

Examples

Let’s see a few examples of inserting the element at the Front in the following empty list.

Initial Linked List
Initial Linked List
1. Insertion at Front (20)
1. Insertion at Front (20)
1. Insertion at Front (20)
  • The insertion is straightforward here since the linked list is empty.
2. Insertion at Front (10)
2. Insertion at Front (10)
2. Insertion at Front (10)
  • Insert element (10) before the first node (20).
  • The Head points to the new node after insertion.

3.2. Insert After

Connect the new Node after the given Node, and link the rest of the list after the new Node.

Algorithm

  1. Create the new node.
  2. Link the new node after the given node.

Examples

1. Insertion of new Node (15) after the Node (10)
1. Insertion of new Node (15) after the Node (10)
1. Insertion of new Node (15) after the Node (10)
  • Here, we create a new node and link it between node (10) and node (20)

3.3. Delete Front

Change the Head pointer to point to the second node, and delete the Front node.

Algorithm

  1. Check if the list is empty and return if true.
  2. Store the reference to the front node as the target node. Subsequently, move the head to the next node if available or NULL.
  3. Finally, delete the target node.

Examples

Let’s consider the following linked list and perform deletions.

Linked List Before Deletion
Linked List Before Deletion
1. Delete the Front Node (10)
1. Delete the Front Node (10)
1. Delete the Front Node (10)
  • Deleting the front node is straightforward. So, we need to move the Head to the next node.

3.4. Delete After

A node can be removed from the linked list by directly connecting its previous and next node.

Algorithm

  1. Store the reference to the target node.
  2. Check if the target node is NULL and return if true.
  3. Disconnect the target node by linking its previous and next node directly.
  4. Finally, delete the target node.

Examples

Let’s take the following linked list and perform deletion after the node (15)

Linked List before Deletion
Linked List before Deletion
1. Delete the Node (20) located after Node (15)
1. Delete the Node (20) located after Node (15)
1. Delete the Node (20) located after Node (15)
  • Node (20) is located after the given node (15).
  • We need to unlink only the node (20) in the middle and make sure that rest of the list exists.

3.5. Remove the given Element

Check if the element matches with the Front node and invoke delete_front() if true. Otherwise, search for the given Element by iterating the linked list and deleting the particular node if found.

Algorithm

  1. Check if the list is empty and return if true.
  2. Check if the front node matches the element. If true, invoke the delete_front() operation and return.
  3. Otherwise, iterate the linked list from start to end, and search the element.
  4. If found, set the node as the target node and disconnect it by directly linking the previous and next nodes.
  5. Finally, delete the target node

3.6. Search an Element

The list is traversed from start to end to search for an element in the Linked List.

Algorithm

  1. Iterate the linked list from start to end
  2. Check if the element matches, and return the node if found.
  3. Return NULL if none matches.

4. References

Copyright copyright 2024 Simplerize