|
| 1 | +# Linked List Data Structure |
| 2 | + |
| 3 | +Link list is a linear data Structure which can be defined as collection of objects called nodes that are randomly stored in the memory. |
| 4 | +A node contains two types of metadata i.e. data stored at that particular address and the pointer which contains the address of the next node in the memory. |
| 5 | + |
| 6 | +The last element in a linked list features a null pointer. |
| 7 | + |
| 8 | +## Why use linked list over array? |
| 9 | + |
| 10 | +From the beginning, we are using array data structure to organize the group of elements that are stored individually in the memory. |
| 11 | +However, there are some advantage and disadvantage of array which should be known to decide which data structure will used throughout the program. |
| 12 | + |
| 13 | +limitations |
| 14 | + |
| 15 | +1. Before an array can be utilized in a program, its size must be established in advance. |
| 16 | +2. Expanding an array's size is a lengthy process and is almost impossible to achieve during runtime. |
| 17 | +3. Array elements must be stored in contiguous memory locations. To insert an element, all subsequent elements must be shifted |
| 18 | + |
| 19 | +So we introduce a new data structure to overcome these limitations. |
| 20 | + |
| 21 | +Linked list is used because, |
| 22 | +1. Dynamic Memory Management: Linked lists allocate memory dynamically, meaning nodes can be located anywhere in memory and are connected through pointers, rather than being stored contiguously. |
| 23 | +2. Adaptive Sizing: There is no need to predefine the size of a linked list. It can expand or contract during runtime, adapting to the program's requirements within the constraints of the available memory. |
| 24 | + |
| 25 | +Let's code something |
| 26 | + |
| 27 | +The smallest Unit: Node |
| 28 | + |
| 29 | +```python |
| 30 | + class Node: |
| 31 | + def __init__(self, data): |
| 32 | + self.data = data # Assigns the given data to the node |
| 33 | + self.next = None # Initialize the next attribute to null |
| 34 | +``` |
| 35 | + |
| 36 | +Now, we will see the types of linked list. |
| 37 | + |
| 38 | +There are mainly four types of linked list, |
| 39 | +1. Singly Link list |
| 40 | +2. Doubly link list |
| 41 | +3. Circular link list |
| 42 | +4. Doubly circular link list |
| 43 | + |
| 44 | + |
| 45 | +## 1. Singly linked list. |
| 46 | + |
| 47 | +Simply think it is a chain of nodes in which each node remember(contains) the addresses of it next node. |
| 48 | + |
| 49 | +### Creating a linked list class |
| 50 | +```python |
| 51 | + class LinkedList: |
| 52 | + def __init__(self): |
| 53 | + self.head = None # Initialize head as None |
| 54 | +``` |
| 55 | + |
| 56 | +### Inserting a new node at the beginning of a linked list |
| 57 | + |
| 58 | +```python |
| 59 | + def insertAtBeginning(self, new_data): |
| 60 | + new_node = Node(new_data) # Create a new node |
| 61 | + new_node.next = self.head # Next for new node becomes the current head |
| 62 | + self.head = new_node # Head now points to the new node |
| 63 | +``` |
| 64 | + |
| 65 | +### Inserting a new node at the end of a linked list |
| 66 | + |
| 67 | +```python |
| 68 | + def insertAtEnd(self, new_data): |
| 69 | + new_node = Node(new_data) # Create a new node |
| 70 | + if self.head is None: |
| 71 | + self.head = new_node # If the list is empty, make the new node the head |
| 72 | + return |
| 73 | + last = self.head |
| 74 | + while last.next: # Otherwise, traverse the list to find the last node |
| 75 | + last = last.next |
| 76 | + last.next = new_node # Make the new node the next node of the last node |
| 77 | +``` |
| 78 | +### Inserting a new node at the middle of a linked list |
| 79 | + |
| 80 | +```python |
| 81 | + def insertAtPosition(self, data, position): |
| 82 | + new_node = Node(data) |
| 83 | + if position <= 0: #check if position is valid or not |
| 84 | + print("Position should be greater than 0") |
| 85 | + return |
| 86 | + if position == 1: |
| 87 | + new_node.next = self.head |
| 88 | + self.head = new_node |
| 89 | + return |
| 90 | + current_node = self.head |
| 91 | + current_position = 1 |
| 92 | + while current_node and current_position < position - 1: #Iterating to behind of the postion. |
| 93 | + current_node = current_node.next |
| 94 | + current_position += 1 |
| 95 | + if not current_node: #Check if Position is out of bound or not |
| 96 | + print("Position is out of bounds") |
| 97 | + return |
| 98 | + new_node.next = current_node.next #connect the intermediate node |
| 99 | + current_node.next = new_node |
| 100 | +``` |
| 101 | +### Printing the Linked list |
| 102 | + |
| 103 | +```python |
| 104 | + def printList(self): |
| 105 | + temp = self.head # Start from the head of the list |
| 106 | + while temp: |
| 107 | + print(temp.data,end=' ') # Print the data in the current node |
| 108 | + temp = temp.next # Move to the next node |
| 109 | + print() # Ensures the output is followed by a new line |
| 110 | +``` |
| 111 | + |
| 112 | +Lets complete the code and create a linked list. |
| 113 | + |
| 114 | +Connect all the code. |
| 115 | + |
| 116 | +```python |
| 117 | + if __name__ == '__main__': |
| 118 | + llist = LinkedList() |
| 119 | + |
| 120 | + # Insert words at the beginning |
| 121 | + llist.insertAtBeginning(4) # <4> |
| 122 | + llist.insertAtBeginning(3) # <3> 4 |
| 123 | + llist.insertAtBeginning(2) # <2> 3 4 |
| 124 | + llist.insertAtBeginning(1) # <1> 2 3 4 |
| 125 | + |
| 126 | + # Insert a word at the end |
| 127 | + llist.insertAtEnd(10) # 1 2 3 4 <10> |
| 128 | + llist.insertAtEnd(7) # 1 2 3 4 10 <7> |
| 129 | + |
| 130 | + #Insert at a random position |
| 131 | + llist.insertAtPosition(9,4) ## 1 2 3 <9> 4 10 7 |
| 132 | + # Print the list |
| 133 | + llist.printList() |
| 134 | +``` |
| 135 | + |
| 136 | +## output: |
| 137 | +1 2 3 9 4 10 7 |
| 138 | + |
| 139 | + |
| 140 | +### Deleting a node from the beginning of a linked list |
| 141 | +check the list is empty otherwise shift the head to next node. |
| 142 | +```python |
| 143 | + def deleteFromBeginning(self): |
| 144 | + if self.head is None: |
| 145 | + return "The list is empty" # If the list is empty, return this string |
| 146 | + self.head = self.head.next # Otherwise, remove the head by making the next node the new head |
| 147 | +``` |
| 148 | +### Deleting a node from the end of a linked list |
| 149 | + |
| 150 | +```python |
| 151 | + def deleteFromEnd(self): |
| 152 | + if self.head is None: |
| 153 | + return "The list is empty" |
| 154 | + if self.head.next is None: |
| 155 | + self.head = None # If there's only one node, remove the head by making it None |
| 156 | + return |
| 157 | + temp = self.head |
| 158 | + while temp.next.next: # Otherwise, go to the second-last node |
| 159 | + temp = temp.next |
| 160 | + temp.next = None # Remove the last node by setting the next pointer of the second-last node to None |
| 161 | +``` |
| 162 | + |
| 163 | + |
| 164 | +### Search in a linked list |
| 165 | +```python |
| 166 | + def search(self, value): |
| 167 | + current = self.head # Start with the head of the list |
| 168 | + position = 0 # Counter to keep track of the position |
| 169 | + while current: # Traverse the list |
| 170 | + if current.data == value: # Compare the list's data to the search value |
| 171 | + return f"Value '{value}' found at position {position}" # Print the value if a match is found |
| 172 | + current = current.next |
| 173 | + position += 1 |
| 174 | + return f"Value '{value}' not found in the list" |
| 175 | +``` |
| 176 | + |
| 177 | +```python |
| 178 | + if __name__ == '__main__': |
| 179 | + llist = LinkedList() |
| 180 | + |
| 181 | + # Insert words at the beginning |
| 182 | + llist.insertAtBeginning(4) # <4> |
| 183 | + llist.insertAtBeginning(3) # <3> 4 |
| 184 | + llist.insertAtBeginning(2) # <2> 3 4 |
| 185 | + llist.insertAtBeginning(1) # <1> 2 3 4 |
| 186 | + |
| 187 | + # Insert a word at the end |
| 188 | + llist.insertAtEnd(10) # 1 2 3 4 <10> |
| 189 | + llist.insertAtEnd(7) # 1 2 3 4 10 <7> |
| 190 | + |
| 191 | + #Insert at a random position |
| 192 | + llist.insertAtPosition(9,4) # 1 2 3 <9> 4 10 7 |
| 193 | + llist.insertAtPositon(56,4) # 1 2 3 <56> 9 4 10 7 |
| 194 | + |
| 195 | + #delete at the beginning |
| 196 | + llist.deleteFromBeginning() # 2 3 56 9 4 10 7 |
| 197 | + |
| 198 | + #delete at the end |
| 199 | + llist.deleteFromEnd() # 2 3 56 9 4 10 |
| 200 | + # Print the list |
| 201 | + llist.printList() |
| 202 | +``` |
| 203 | +## Output: |
| 204 | + |
| 205 | +2 3 56 9 4 10 |
| 206 | + |
| 207 | + |
| 208 | + |
| 209 | +## Real Life uses of Linked List |
| 210 | + |
| 211 | + |
| 212 | +Here are a few practical applications of linked lists in various fields: |
| 213 | + |
| 214 | +1. **Music Player**: In a music player, songs are often linked to the previous and next tracks. This allows for seamless navigation between songs, enabling you to play tracks either from the beginning or the end of the playlist. This is akin to a doubly linked list where each song node points to both the previous and the next song, enhancing the flexibility of song selection. |
| 215 | + |
| 216 | +2. **GPS Navigation Systems**: Linked lists can be highly effective for managing lists of locations and routes in GPS navigation systems. Each location or waypoint can be represented as a node, making it easy to add or remove destinations and to navigate smoothly from one location to another. This is similar to how you might plan a road trip, plotting stops along the way in a flexible, dynamic manner. |
| 217 | + |
| 218 | +3. **Task Scheduling**: Operating systems utilize linked lists to manage task scheduling. Each process waiting to be executed is represented as a node in a linked list. This organization allows the system to efficiently keep track of which processes need to be run, enabling fair and systematic scheduling of tasks. Think of it like a to-do list where each task is a node, and the system executes tasks in a structured order. |
| 219 | + |
| 220 | +4. **Speech Recognition**: Speech recognition software uses linked lists to represent possible phonetic pronunciations of words. Each potential pronunciation is a node, allowing the software to dynamically explore different pronunciation paths as it processes spoken input. This method helps in accurately recognizing and understanding speech by considering multiple possibilities in a flexible manner, much like evaluating various potential meanings in a conversation. |
| 221 | + |
| 222 | +These examples illustrate how linked lists provide a flexible, dynamic data structure that can be adapted to a wide range of practical applications, making them a valuable tool in both software development and real-world problem-solving. |
0 commit comments