For working professionals
For fresh graduates
More
Data Structure Tutorial: Every…
1. Data Structure
2. Types of Linked Lists
3. Array vs Linked Lists in Data Structure
4. Stack vs. Queue Explained
5. Singly Linked List
Now Reading
6. Circular doubly linked list
7. Circular Linked List
8. Stack Implementation Using Array
9. Circular Queue in Data Structure
10. Dequeue in Data Structures
11. Bubble Sort Algorithm
12. Insertion Sort Algorithm
13. Shell Sort Algorithm
14. Radix Sort
15. Counting Sort Algorithm
16. Trees in Data Structure
17. Tree Traversal in Data Structure
18. Inorder Traversal
19. Optimal Binary Search Trees
20. AVL Tree
21. Red-Black Tree
22. B+ Tree in Data Structure
23. Expression Tree
24. Adjacency Matrix
25. Spanning Tree in Data Structure
26. Kruskal Algorithm
27. Prim's Algorithm in Data Structure
28. Bellman Ford Algorithm
29. Ford-Fulkerson Algorithm
30. Trie Data Structure
31. Floyd Warshall Algorithm
32. Rabin Karp Algorithm
33. What Is Dynamic Programming?
34. Longest Common Subsequence
35. Fractional Knapsack Problem
36. Greedy Algorithm
37. Longest Increasing Subsequence
38. Matrix Chain Multiplication
39. Subset Sum Problem
40. Backtracking Algorithm
41. Huffman Coding Algorithm
42. Tower of Hanoi
43. Stack vs Heap
44. Asymptotic Analysis
45. Binomial Distribution
46. Coin Change Problem
47. Fibonacci Heap
48. Skip List in Data Structure
49. Sparse Matrix
50. Splay Tree
51. Queue in Data Structure
52. Stack in Data Structure
53. Time and Space Complexity
54. Linked List in Data Structure
55. Stack And Queue: Roles & Functions
56. Doubly Linked List
57. Strongly Connected Components
58. Bucket Sort Algorithm
A singly linked list is a dynamic and flexible data structure that allows you to store elements in a non-contiguous manner with each element linked to the next via pointers. This means that you can easily add or remove elements without the constraints of fixed memory allocation.
The concept of singly linked lists dates back to the earliest days of computers. It has developed throughout time and is now used in a variety of disciplines, including computer languages and database systems.
Nearly every major programming language, including Python, Java, and C++, has its implementation of singly linked lists. Singly-linked lists are integral components of modern computing, powering everything from basic algorithms to complex data structures.
In this article, I will explain singly linked lists in detail. We will discuss its implementation, operations, and much more.
A singly linked list is a type of linked list that acts like a chain of connected elements, known as nodes, where each node contains both data and a pointer to the next node in the sequence. This unidirectional structure means you can traverse the list from the starting point, called the head and all the way to the end, known as the tail.
Nodes in a singly linked list data structure hold valuable information, along with a reference to the next node, ensuring the continuity of the sequence. The head serves as the entry point, providing access to the first node, while the tail signifies the end of the list, pointing to NULL.
By the end of this guide, you will understand singly linked lists and how they work. You will also learn how to perform operations like delete and insert on singly linked lists.
A singly linked list is a foundational data structure in computer science and programming that plays an important role in managing and organizing data.
A singly linked list is a collection of nodes, where each node contains two components: data and a reference (or pointer) to the next node in the sequence. This structure forms a linear chain, with each node pointing to the next until the end of the list is reached. This sequential arrangement facilitates quick and easy traversal from one node to another.
Singly-linked lists offer flexibility and efficiency in managing dynamic collections of data. One common type of singly linked list is the circular singly linked list. In a circular singly linked list, the last node of the list is linked to the first node of the list, creating a circular structure.
Let's break down the anatomy of a node in a singly linked list:
In a singly linked list, the space complexity scales linearly with the number of nodes, resulting in O(n) space complexity as each node contains a reference to the next node. Furthermore, the time complexity for inserting and deleting an element from the list is also O(n) due to the need to traverse the list to locate the appropriate position.
In a singly linked list, accessing elements, as well as insertion at the beginning and end, generally requires traversing the list, resulting in a time complexity of O(n). However, the space complexity remains constant at O(1) regardless of the number of elements in the list.
Operation | Time Complexity (Singly Linked List) | Space Complexity |
Accessing by Index | O(n) | O(1) |
Insertion at Beginning | O(1) | O(1) |
Insertion at End | O(n) | O(1) |
Insertion at Given Position | O(n) | O(1) |
In programming, implementing a singly linked list often involves defining a node class or struct to encapsulate the node's properties. Let's illustrate this with a simple python example: To create a singly linked list in python use the following code:
class Node:
def __init__(self, data):
self.data = data
self.next = None
# Example usage
node1 = Node(10)
node2 = Node(20)
node3 = Node(30)
node1.next = node2
node2.next = node3
The singly linked list nodes
class Node:
def __init__(self, data):
self.data = data
self.next = None
In this example, we define a Node class with two attributes: data and next. We then create instances of the Node class and link them together to form a singly linked list.
Singly linked lists offer a variety of operations to manage and manipulate data they contain. These operations help you to interact with singly linked lists. Here are the operations:
Here are the time and space complexity for each operation:
Operation | Time Complexity (TC) | Space Complexity (SC) |
Traversing | O(n) | O(1) |
Searching | O(n) | O(1) |
Finding | O(n) | O(1) |
Insertion | O(1) | O(1) |
Deletion | O(1) | O(1) |
Reversing | O(n) | O(1) |
Let's discuss each of these operations in detail.
Traversal is the process of visiting each node in the linked list sequentially and performing some operation on the data contained within each node. This operation could involve printing the data, searching for specific values, or performing calculations.
To traverse a singly linked list, you can follow these steps:
Here's a simple example of traversing a singly linked list in Python:
class Node:
def __init__(self, data):
self.data = data
self.next = None
# Function to traverse the linked list and print data of each node
def traverse_linked_list(head):
current = head
while current is not None:
print(current.data)
current = current.next
# Example usage
node1 = Node(10)
node2 = Node(20)
node3 = Node(30)
# Linking the nodes together
node1.next = node2
node2.next = node3
# Traverse the linked list
traverse_linked_list(node1)
In a singly linked list data structure, searching is identifying a certain element or value among the linked list's elements. Here are the steps to perform searching in a singly linked list:
Here's an implementation of the search operation in Java:
public class Node {
int data;
Node next;
Node(int data) {
this.data = data;
this.next = null;
}
}
public class SinglyLinkedList {
// search for a value inside the Linked List
public boolean searchLinkedList(Node head, int target) {
// Traverse the Linked List
while (head != null) {
// Check the node's target value
if (head.data == target) {
return true; // Value found
}
// Move to the next node
head = head.next;
}
return false; // Value not found
}
}
Finding the length of a singly linked list involves determining the number of nodes present in the list. It is similar to counting the number of books on a shelf. You need to go through each book and keep track of how many you have counted. Here are the steps to find the length of a singly linked list:
Here is an example in data structure on the implementation of finding the length of a singly linked list in Java:
public class SinglyLinkedList {
// Function to find the length of the linked list
public int findLength(Node head) {
// start counter
int length = 0;
// Start it from the head
Node current = head;
// Traverse the list and increment the length for each node
while (current != null) {
length++;
current = current.next;
}
// Return the final length of the linked list
return length;
}
}
Insertion is a key operation in linked lists, allowing you to add new nodes to the list. Here is the
insertion algorithm for singly linked list in data structure:
If PTR is NULL, write "OVERFLOW" and exit.
Set NEW_NODE to PTR.
Set PTR to PTR's next node.
Set NEW_NODE's data to VAL.
Set NEW_NODE's next node to HEAD.
Set HEAD to NEW_NODE.
Exit.
Let's discuss three common scenarios for insertion:
To insert a node at the beginning, follow these steps:
Here is an example on how you can implement this in Java:
public class LinkedList {
private Node head;
public void insertAtBeginning(int newData) {
Node newNode = new Node(newData); // Create a new node
newNode.next = head; // Link the new node to the current head
head = newNode; // Update the head to the new node
}
}
To insert a node at the end, you need to:
In Java, it is implemented as follows:
public class LinkedList {
private Node head;
public void insertAtEnd(int newData) {
Node newNode = new Node(newData); // Create a new node
if (head == null) { // If the list is empty
head = newNode; // Make the new node the head
return;
}
Node last = head;
while (last.next != null) {
last = last.next; // Traverse until the last node
}
last.next = newNode; // Link the new node to the last node
}
}
To insert a node at a specific position, follow these steps:
Insert the new node at the specified position by updating the links accordingly.
Deleting a node from a linked list is another fundamental operation and it involves removing a specific node from the list. Like insertion and deletion may occur in a variety of ways.
To delete the first node, you simply need to update the head of the list to point to the second node. This is how you can use Java to do it:
public class LinkedList {
private Node head;
// Method to delete a node at the beginning of the list
public void deleteAtBeginning() {
if (head == null) { // If the list is empty
System.out.println("List is empty. Cannot delete from the beginning.");
return;
}
Node temp = head; // Store the current head in a temporary variable
head = head.next; // Update it’s head
temp = null; // Delete the old head node
}
}
To delete the last node, you need to traverse the list until the second-to-last node and update its next field to null. Here is its Java implementation:
public class LinkedList {
private Node head;
// Method to delete a node at the end of the list
public void deleteAtEnd() {
if (head == null) { // If the list is empty
System.out.println("List is empty. Cannot delete from the end.");
return;
}
if (head.next == null) { // If there is only one node
head = null;
return;
}
Node current = head;
while (current.next.next != null) { // Traverse to the second-to-last node
current = current.next;
}
current.next = null; // Delete the last node
}
}
To delete a node at a specific position, you traverse the list to the desired position and update the links to bypass the node to be deleted.
Reversing a singly linked list involves changing the direction of pointers so that the last node becomes the first node and vice versa. This operation is essential for various applications, such as efficiently traversing the list in reverse order or solving certain algorithmic problems.
To reverse a singly linked list, you typically iterate through the list while maintaining references to the previous, current, and next nodes. You update the next pointer of each node to point to its previous node, effectively reversing the direction of the list.
Let's explore the Python code to implement this:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def reverse(self):
prev_node = None
current_node = self.head
while current_node:
next_node = current_node.next # Store the next node
current_node.next = prev_node # Reverse the pointer
prev_node = current_node # Move prev_node to current_node
current_node = next_node # Move current_node to next_node
self.head = prev_node # Update the head to the last node (prev_node)
def print_list(self):
current_node = self.head
while current_node:
print(current_node.data, end=" ")
current_node = current_node.next
print()
# Example usage
linked_list = LinkedList()
linked_list.head = Node(1)
second_node = Node(2)
third_node = Node(3)
linked_list.head.next = second_node
second_node.next = third_node
print("Original Linked List:")
linked_list.print_list()
linked_list.reverse()
print("Reversed Linked List:")
linked_list.print_list()
In this implementation, we define a Node class to represent each node in the linked list and a LinkedList class to manage the list. The reverse method of the LinkedList class iterates through the list, reversing the pointers of each node. Finally, we demonstrate the reversal operation with an example usage.
Commonly used data structures like singly linked lists and doubly linked lists offer different features and efficiencies, each suited to specific use cases. Additionally, arrays provide a more traditional data storage option with distinct advantages and limitations. Let’s compare them.
Comparison | Singly Linked List | Doubly Linked List | Arrays |
Memory Usage | Requires less memory as it only stores a next pointer for each node. | Requires more memory as it stores both next and previous pointers for each node. | Memory usage depends on the size of the array and the sorted data type. |
Insertion/Deletion Efficiency | Efficient for insertion and deletion at the beginning and end of the list. | Efficient for insertion and deletion at any position in the list. | Efficient for random access insertion and deletion, but less efficient for insertion and deletion in the middle. |
Traversal Efficiency | Traversal is efficient in a forward direction. | Traversal is efficient in both forward and backward directions. | Traversal is efficient, especially for sequential access. |
Flexibility in Operations | Limited flexibility due to unidirectional links. | More flexible due to bidirectional links, allowing efficient backward traversal and manipulation. | Offers flexibility in various operations, including insertion, deletion, and access. |
Usage | Suitable for scenarios where forward traversal and efficient insertion/deletion at the beginning or end are frequent operations. | Suitable for scenarios requiring frequent traversal in both forward and backward directions and efficient insertion/deletion at any position. | Suitable for scenarios requiring random access and efficient insertion/deletion at any position. |
Singly linked lists find applications in various real-world scenarios across different domains. Here is a brief discussion of some common singly linked list applications and use cases:
Memory management systems frequently use singly linked lists. For example, operating systems use linked lists to manage dynamic memory allocation and deallocation, such as maintaining lists of free memory blocks and allocating memory to processes.
To manage tasks in applications like to-do lists or task schedulers, singly linked lists offer flexibility in adding, removing, and updating tasks. Each task can be represented as a node in the list, allowing you to efficiently organize and manipulate tasks.
Navigation systems show pathways or routes using singly linked lists. Each node in the list can represent a location or waypoint and the links between nodes define the sequence of locations to traverse. This application is particularly useful in GPS navigation systems.
Many software applications, such as text editors or graphic design tools, implement undo/redo functionality using singly linked lists. Each action performed by the user, such as typing a character or drawing a shape, is recorded as a node in the list. Users can then undo or redo actions by traversing backward or forward through the list.
Singly linked lists are used in operating systems to implement queues for managing tasks or processes. For example, the job scheduling subsystem of an operating system may use a singly linked list to maintain a queue of processes waiting to be executed.
In conclusion, singly linked lists serve as essential data structures with versatile applications across various domains. They provide efficient memory management solutions, facilitate task organization, power navigation systems, and enable undo/redo functionality in software applications. Singly linked lists also support queue management in operating systems.
Therefore, with their simplicity and flexibility, there is no doubt that singly linked lists continue to play a crucial role in modern computing, offering effective solutions for dynamic data management needs
Author
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918045604032
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.