What is the concept behind a linked list?

Dec 17, 2024

A linked list is a data structure that consists of a sequence of nodes, where each node contains a value and a reference to the next node in the sequence. The last node in the sequence has a reference to null, indicating the end of the list.

Linked List

Linked lists are useful when the size of the data is not known in advance or when the data needs to be dynamically added or removed. They are also used in many applications, such as implementing stacks and queues.

Here is an example of a simple linked list in C++:

#include <iostream>
using namespace std;

class LinkedList {
public:
	int data;
	LinkedList *next;

	// constructor
	LinkedList(int data, LinkedList *next = nullptr) : data(data), next(next) {}
};

int main() {
    // Step 1: Create nodes in a forward-chained manner
    LinkedList* third = new LinkedList(3);
    LinkedList* second = new LinkedList(2, third);
    LinkedList* head = new LinkedList(1, second);

    // Print the linked list starting from the head
    LinkedList* current = head; // Start from head
    while (current != nullptr) {
        cout << current->data << " ";
        current= current->next;
    }
    cout << endl;

    return 0;
}

Output:

1 2 3

Linked list vs Array (in terms of memory allocation):

  • An array of size 7:
int arr[7] = {50, 51, 52, 53, 54, 55, 56};
Memory allocation in an array

Elements are stored in contiguous memory, with addresses accessible using indices.

  • Memory alocation in a LinkedList:
Memory allocation in a linked list

Each node is stored in a separate memory location, with references pointing to the next node.

Memory allocation in a linked list

Couple of methods associated with Singly Linked List:

  • Convert the vector into a linkedlist
// convert the vector into a linkedlist
	LinkedList *arrayToLinkedList(vector<int> &arr)
	{
		if (arr.size() == 0)
			return nullptr;

		LinkedList *head = new LinkedList(arr[0]);
		LinkedList *mover = head;

		for (int i = 1; i < arr.size(); i++)
		{
			LinkedList *temp= new LinkedList(arr[i]);
			mover->next = temp;
			mover = temp;
		}

		return head;
	}
  • Display the elements in the linkedlist
// display the elements in the linkedlist
	void printLinkedList(LinkedList *head)
	{
		if (head == nullptr)
		{
			cout << "The linkedlist is empty!" << endl;
			return;
		}
		else
		{
			LinkedList *temp = head;
			while (temp)
			{
				cout << temp->data << "->";
				temp = temp->next;
			}
			cout << "null" << endl;
		}
	}
  • Display the elements in the circular linkedlist
	void printCircularLinkedList(LinkedList *head)
	{
		if (head == nullptr)
		{
			cout << "The linkedlist is empty!" << endl;
			return;
		}
		else
		{
			LinkedList *temp = head;
			do
			{
				cout << temp->data << "->";
				temp = temp->next;
			} while (temp != head);
			cout << head->data << endl;
		}
	}
  • Check if the linkedlist is empty
// check if the linkedlist is empty
	bool isNull(LinkedList *head)
	{
		if (head == nullptr)
		{
			cout << "The linkedlist is empty!" << endl;
			return true;
		}
		return false;
	}
  • Length of the linkedlist
// length of the linkedlist
	int length(LinkedList *head)
	{
		if (head == nullptr)
			return 0;
		int count = 0;

		LinkedList *temp = head;
		while (temp != nullptr)
		{
			temp = temp->next;
			count++;
		}
		return count;
	}
  • Check if there is a loop in the linkedlist using tortise and hare method
	bool isLoop(LinkedList *head)
	{
		if (isNull(head))
			return false;
		else if (head->next == nullptr)
			return false;
		else
		{
			LinkedList *slow = head;
			LinkedList *fast = head;

			while (fast != nullptr && fast->next != nullptr)
			{
				slow = slow->next;
				fast = fast->next->next;

				if (slow == fast)
				{
					return true;
				}
			}
		}
		return false;
	}
  • Check if the linkedlist is circular
	bool isCircular(LinkedList *head)
	{
		if (isNull(head))
			return false;
		else if (head->next == nullptr)
			return false;

		LinkedList *temp = head;
		while (temp != nullptr && temp != head)
		{
			temp = temp->next;
		}

		return (temp == head);
	}
  • Delete the linkedlist
	void deleteLinkedList(LinkedList *head)
	{
		LinkedList *temp;
		while (head != nullptr)
		{
			temp = head;
			head = head->next;
			delete temp;
		}
	}
  • Delete the circular linkedlist
	void deleteCircularLinkedList(LinkedList *list)
	{
		LinkedList *temp = list->next;
		list->next = nullptr;
		deleteLinkedList(temp);

		delete list;
	}
  • Add elements at the start of the linkedlist
	// adding elements
	LinkedList *addElementAtStart(LinkedList *head, int ele)
	{
		if (head == nullptr)
		{
			head = new LinkedList(ele);
			return head;
		}

		LinkedList *temp = new LinkedList(ele);
		temp->next = head;
		head = temp;

		return head;
	}
  • Add elements at the end of the linkedlist
	LinkedList *addElementAtEnd(LinkedList *head, int ele)
	{
		if (head == nullptr)
		{
			head = new LinkedList(ele);
			return head;
		}

		LinkedList *tail = new LinkedList(ele);

		LinkedList *temp = head;
		while (temp->next != nullptr)
		{
			temp = temp->next;
		}

		temp->next = tail;

		return head;
	}
  • Add elements at a specific position in the linkedlist
	LinkedList *addElementAtPos(LinkedList *head, int ele, int pos)
	{
		if (pos < 1)
		{
			cout << "Invalid position, must be >= 1." << endl;
			return head; // Invalid position
		}

		if (pos == 1)
		{ // Insert at head
			return addElementAtStart(head, ele);
		}

		int len = length(head);
		if (pos > len + 1)
		{ // Allow insertion at the end
			cout << "Position " << pos << " is out of bounds" << endl;
			return head;
		}

		LinkedList *temp = head;
		int count = 1; // Start counting from 1
		while (temp && count < pos - 1)
		{
			temp = temp->next; // Move to the node before the position
			count++;
		}

		LinkedList *newNode = new LinkedList(ele);
		newNode->next = temp->next; // Insert new node at the position
		temp->next = newNode;

		return head; // Return the head of the linked list
	}
  • Delete the head of the linkedlist
// delete nodes in the linked list
	void deleteHead(LinkedList *head)
	{
		if (isNull(head))
			return;
		LinkedList *temp = head;
		head = head->next;
		delete temp;
	}
  • Delete the tail of the linkedlist
	LinkedList *deleteTail(LinkedList *head)
	{
		if (isNull(head))
			return nullptr;

		if (head->next == nullptr)
		{ // Only one element
			delete head;
			return nullptr;
		}

		LinkedList *temp = head;
		while (temp->next->next != nullptr)
		{ // Stop at the second last node
			temp = temp->next;
		}

		delete temp->next;	  // Delete the last node
		temp->next = nullptr; // Set the second last node's next to nullptr

		return head; // Return the updated head
	}
  • Delete a node in the linkedlist
	LinkedList *deleteNode(LinkedList *head, int data)
	{
		if (isNull(head))
			return nullptr;
		if (head->data == data)
		{
			LinkedList *newHead = head->next;
			delete head;
			return newHead;
		}

		LinkedList *temp = head;
		while (temp->next != nullptr)
		{
			if (temp->next->data == data)
			{
				LinkedList *nodeToDelete = temp->next;
				temp->next = temp->next->next;
				delete nodeToDelete;
				return head;
			}
			temp = temp->next;
		}

		return head;
	}
  • Delete a node at a specific position in the linkedlist
	LinkedList *deleteNodeAtPos(LinkedList *head, int pos)
	{
		if (isNull(head))
		{
			cout << "Invalid position value, the linked list is empty." << endl;
			return nullptr;
		}

		if (pos == 1)
		{
			LinkedList *newHead = head->next;
			delete head;	// Free the old head
			return newHead; // Return the new head
		}

		int len = length(head);

		if (pos > len || pos < 1)
		{
			cout << "Invalid position value, the position " << pos << " exceeds the length of the linked list provided." << endl;
			return head; // Return the unchanged head
		}

		// Handle case for deleting the tail node
		if (pos == len)
		{
			return deleteTail(head); // Use your existing deleteTail function
		}

		// Find the node before the one we want to delete
		LinkedList *temp = head;
		int count = 1; // Start counting from 1
		while (temp != nullptr && count < pos - 1)
		{
			temp = temp->next; // Move to the next node
			count++;
		}

		if (temp != nullptr && temp->next != nullptr)
		{
			LinkedList *nodeToDelete = temp->next; // The node to delete
			temp->next = nodeToDelete->next;	   // Bypass the node to delete
			delete nodeToDelete;				   // Delete the node
		}

		return head; // Return the head of the linked list
	}
  • Reverse a singly linked list
// reverse a singly linked list
	LinkedList *reverse(LinkedList *head)
	{ // TC: O(2N), SC: O(1)
		if (head == NULL || head->next == NULL)
			return head;

		LinkedList *temp = head;
		LinkedList *prevNode = NULL;

		while (temp)
		{
			LinkedList *nextNode = temp->next;
			temp->next = prevNode;
			prevNode = temp;
			temp = nextNode;
		}
		return prevNode;
	}
  • Sort a singly linked list using merge sort
// sort a singly linked list
	LinkedList *helper_findMiddle(LinkedList *head)
	{
		LinkedList *slow = head;
		LinkedList *fast = head->next;

		while (fast != NULL && fast->next != NULL)
		{
			slow = slow->next;
			fast = fast->next->next;
		}
		return slow;
	}

	LinkedList *helper_merge(LinkedList *list1, LinkedList *list2)
	{
		LinkedList *dummyNode = new LinkedList(-1);
		LinkedList *temp = dummyNode;
		while (list1 != NULL && list2 != NULL)
		{
			if (list1->data < list2->data)
			{
				temp->next = list1;
				temp = list1;
				list1 = list1->next;
			}
			else
			{
				temp->next = list2;
				temp = list2;
				list2 = list2->next;
			}
		}
		if (list1)
			temp->next = list1;
		else
			temp->next = list2;

		return dummyNode->next;
	}

	LinkedList *sort(LinkedList *head)
	{

		if (head == NULL || head->next == NULL)
		{
			return head;
		}

		LinkedList *middle = helper_findMiddle(head);
		LinkedList *rightHead = middle->next;
		LinkedList *leftHead = head;

		middle->next = NULL;

		leftHead = sort(leftHead);
		rightHead = sort(rightHead);

		return helper_merge(leftHead, rightHead);
	}
  • Remove duplicates from a singly linkedlist
	// remove duplicates from a singly linkedlist
	LinkedList *removeDuplicates(LinkedList *head)
	{
		if (head == nullptr)
			return nullptr; // Return nullptr for an empty list

		LinkedList *temp = head;
		while (temp != nullptr)
		{
			LinkedList *curr = temp;
			while (curr->next != nullptr && curr->data == curr->next->data)
			{
				curr->next = curr->next->next; // Skip duplicates
			}
			temp = temp->next; // Move to the next unique element
		}
		return head; // Return the modified list
	}
Mounish Vatti