A linked list is represented by a pointer to the first node of the linked list. The first node is called head. If the linked list is empty, then value of head is NULL.
Each node in a list consists of at least two parts:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def list_length(self):
temp = self.head
length = 0
while(temp):
length += 1
temp = temp.next
return length
def print_list(self):
n = self.list_length()
temp = self.head
print('''+---+---+ '''*n)
while(temp):
print("| {} | •-|--->".format(temp.data), end="")
temp = temp.next
print("Null")
print('''+---+---+ '''*n)
def push(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
print("Linked List:")
linked_list = LinkedList()
linked_list.push(5)
linked_list.push(2)
linked_list.push(7)
linked_list.push(4)
linked_list.print_list()
Output:
Given a linked list need to insert a node in it.
Example:
Linked List at Start: 5–>1–>6–>7—>Null
After push(3): 3–>5–>1–>6–>7–>Null
After insert_at(4, 9): 3–>5–>1–>9–>6–>7–>Null
After append(2): 3–>5–>1–>9–>6–>7–>2–>Null
A node can be inserted in 3 ways:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def print_list(self):
temp = self.head
while(temp):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("Null")
def push(self, data):
# Make a new_node.
new_node = Node(data)
# (1) Next of new_node points to node where head was poiting earlier.
new_node.next = self.head
# (2) Now, head points to new_node.
self.head = new_node
def append(self, data):
# Make a new_node.
new_node = Node(data)
# (1) Find the last node using temp and make the next of last_node point to new_node.
temp = self.head
while(temp.next):
temp = temp.next
temp.next = new_node
def insert_at(self, position, data):
# If position is 0 call push to insert at front.
if(position == 0):
self.push(data)
return
# Now find position to insert, need to jump only position-2 coz already at 1 and need to go 1 less.
# (Example-1: if position=5, already at 1 so ust 3 jumps to reach 4th posittion.)
temp = self.head
while(temp.next and position-2 > 0):
temp = temp.next
position -= 1
# Make new_node
new_node = Node(data)
# (1) Next of new_node points to next of temp.
new_node.next = temp.next
# (2) Next of temp points to new_node.
temp.next = new_node
print("Linked List at Start:")
linked_list = LinkedList()
linked_list.push(7)
linked_list.push(6)
linked_list.push(1)
linked_list.push(5)
linked_list.print_list()
print("\nAfter push(3):")
linked_list.push(3)
linked_list.print_list()
print("\nAfter insert_at(4, 9):")
linked_list.insert_at(4, 9)
linked_list.print_list()
print("\nAfter append(2):")
linked_list.append(2)
linked_list.print_list()
Output
Given a linked list need to delete a node from it. We will only delete the first occurrence of it.
Example:
Linked List at Start: 4–>7–>6–>3–>5–>Null
After delete(6): 4–>7–>3–>5–>Null
After delete(4): 7–>3–>5–>Null
After delete(2): 7–>3–>5–>Null
Element 2 not present in list.
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def print_list(self):
temp = self.head
while(temp):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("Null")
def push(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def delete(self, data):
temp = self.head
# Check if first node is the node to be deleted if it is
# point the head to next of temp and make temp None.
if(temp and temp.data == data):
self.head = temp.next
temp = None
return
# Search for the node to be deleted using the given data in the nodes
# using temp and keep prev in store.
while(temp):
if(temp.data == data):
break
prev = temp
temp = temp.next
# Point the next of prev to the next of temp and make temp None
# if temp exists else element not present.
if(temp):
prev.next = temp.next
temp = None
else:
print("Element {} not present in list.".format(data))
print("Linked List at Start:")
linked_list = LinkedList()
linked_list.push(5)
linked_list.push(3)
linked_list.push(6)
linked_list.push(7)
linked_list.push(4)
linked_list.print_list()
print("\nAfter delete(6):")
linked_list.delete(6)
linked_list.print_list()
print("\nAfter delete(4):")
linked_list.delete(4)
linked_list.print_list()
print("\nAfter delete(2):")
linked_list.delete(2)
linked_list.print_list()
Output:
Given pointer to the head node of a linked list, the task is to reverse the linked list. We need to reverse the list by changing links between nodes.
Examples:
Input : 4->7->6->3->5->NULL Output : 5->3->6->7->4->NULL
Input : NULL Output : NULL
Input : 1->NULL Output : 1->NULL
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def print_list(self):
temp = self.head
while(temp):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("Null")
def push(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def reverse(self):
# Take prev_node as None and current_node as first node.
prev_node = None
current_node = self.head
# While current_node doesn't become None keep going:
while(current_node):
# Take the next_node as next of current_node.
next_node = current_node.next
# Make the next of current_node point to prev_node
current_node.next = prev_node
# Update the prev_node as current_node and current_node as next_node
prev_node = current_node
current_node = next_node
# Make head point to prev_node which was the last node and now in reverse it becomes first.
self.head = prev_node
print("Linked List at Start:")
linked_list = LinkedList()
linked_list.push(5)
linked_list.push(3)
linked_list.push(6)
linked_list.push(7)
linked_list.push(4)
linked_list.print_list()
print("\nAfter reverse():")
linked_list.reverse()
linked_list.print_list()
Output:
Write a SortedMerge() function that takes two lists, each of which is sorted in increasing order, and merges the two together into one list which is in increasing order.
SortedMerge() should return the new list. The new list should be made by splicing together the nodes of the first two lists.
Example:
list_1: 1->4->5 list_2: is 2->3->6->8->9 merged_list: 1->2->3->4->5->6->8->9
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def print_list(self):
temp = self.head
while(temp):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("Null")
def push(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def merge_2_sorted_linked_lists(self, sorted_list_2):
# Take 2 pointers temp_1 and temp_2 to track both lists and a stack to put the data.
temp_1 = self.head
temp_2 = sorted_list_2.head
stack = []
# While both temp_1 and temp_2 are exists keep on going:
while(temp_1 and temp_2):
# If data of temp_1 is lesser temp_1 is selected and incremented
# else temp_2 is selected and incrmented.
if(temp_1.data <= temp_2.data):
stack.append(temp_1.data)
temp_1 = temp_1.next
else:
stack.append(temp_2.data)
temp_2 = temp_2.next
# If elements are left in temp_1, push all of them to stack.
while(temp_1):
stack.append(temp_1.data)
temp_1 = temp_1.next
# If elements are left in temp_2, push all of them to stack.
while(temp_2):
stack.append(temp_2.data)
temp_2 = temp_2.next
# Now, finally make head point to None and create the linked_list from popping
# from stack and pushing all nodes to it.
self.head = None
while(stack):
self.push(stack.pop())
print("First Sorted Linked List:")
linked_list_1 = LinkedList()
linked_list_1.push(5)
linked_list_1.push(4)
linked_list_1.push(1)
linked_list_1.print_list()
print("\nSecond Sorted Linked List:")
linked_list_2 = LinkedList()
linked_list_2.push(9)
linked_list_2.push(8)
linked_list_2.push(6)
linked_list_2.push(3)
linked_list_2.push(2)
linked_list_2.print_list()
print("\nMerged List:")
linked_list_1.merge_2_sorted_linked_lists(linked_list_2)
linked_list_1.print_list()
Output:
Given a linked list, write a function to reverse every k nodes.
Examples:
Inputs: 1->2->3->4->5->6->7->8->NULL and k = 3
Output: 3->2->1->6->5->4->8->7->NULL
Inputs: 1->2->3->4->5->6->7->8->NULL and k = 5
Output: 5->4->3->2->1->8->7->6->NULL
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def print_list(self):
temp = self.head
while(temp):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("Null")
def push(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def reverse_in_group_of_size(self, k):
# Take prev as None, start the current_node from first node and
# take an empty stack to store atmost k items.
prev = None
current_node = self.head
stack = []
# Till the current_node is not None.
while(current_node):
count = 0
# Take at most k elements in stack and keep moving the current_node.
while(count<k and current_node):
stack.append(current_node.data)
current_node = current_node.next
count += 1
# After k nodes are pushed to stack current will point to k+1 the node
# but prev will still be unchanged.
# Now start popping from stack and make new_node and check:
while(stack):
new_node = Node(stack.pop())
# If prev is None, then set the head to point to prev
# (it will only happen for the first element when prev is None).
if(prev is None):
self.head = new_node
else: # Else set next of prev as new_node
prev.next = new_node
# Update the prev as new_node.
prev = new_node
print("Linked List at Start:")
linked_list = LinkedList()
linked_list.push(8)
linked_list.push(7)
linked_list.push(6)
linked_list.push(5)
linked_list.push(4)
linked_list.push(3)
linked_list.push(2)
linked_list.push(1)
linked_list.print_list()
print("\nAfter reverse_in_group_of_size(3):")
linked_list.reverse_in_group_of_size(3)
linked_list.print_list()
Output:
Given two numbers represented by two lists, write a function that returns sum list. The sum list is list representation of addition of two input numbers.
Examples:
Inputs: Num1 = 984 (4->8->9) Num2 = 978 (8->7->9) sum = 1962 (1->9->6->2)
Inputs: Num1 = 64957 7->5->9->4->6 Num2 = 48 8->4 sum = 65005 (6->5->0->0->5)
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def print_list(self):
temp = self.head
while(temp):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("Null")
def push(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def add_2_numbers(self, number):
# Take 2 pointers to track both the lists, take carry = 0 and also initialize result list.
temp_1 = self.head
temp_2 = number.head
carry = 0
result = LinkedList()
# Now while any of temp_1 or temp_2 is there keep going.
while(temp_1 or temp_2):
# Get the sum: carry + first_list digit sum if exists
# else 0 + second_list digit sum if exists else 0.
digit_sum = carry + (0 if not temp_1 else temp_1.data) + (0 if not temp_2 else temp_2.data)
# If sum geater than 10 then get the digit and carry separated.
if(digit_sum >= 10):
carry = 1
digit_sum -= 10
else:
carry = 0
# Push the digit to result list and update the temp_1 and temp_2 pointers if exists else None.
result.push(digit_sum)
temp_1 = None if not temp_1 else temp_1.next
temp_2 = None if not temp_2 else temp_2.next
# At the end if carry still is not zero, then push carry also to the result list.
if(carry != 0):
result.push(carry)
# Lastly, set the head of the list as result list's head.
self.head = result.head
print("Example-1:")
print("First Number: {}".format(984))
number_1 = LinkedList()
number_1.push(9)
number_1.push(8)
number_1.push(4)
print("Second Number: {}".format(978))
number_2 = LinkedList()
number_2.push(9)
number_2.push(7)
number_2.push(8)
print("Sum of both:")
number_1.add_2_numbers(number_2)
number_1.print_list()
print("\nExample-2:")
print("First Number: {}".format(64957))
number_1 = LinkedList()
number_1.push(6)
number_1.push(4)
number_1.push(9)
number_1.push(5)
number_1.push(7)
print("Second Number: {}".format(48))
number_2 = LinkedList()
number_2.push(4)
number_2.push(8)
print("Sum of both:")
number_1.add_2_numbers(number_2)
number_1.print_list()
Output:
Check whether a given Linked List contains loop and if loop is present then removes the loop and returns true. And if the list doesn’t contain loop then returns false.
Examples:
Input: 1->2->3->4->5->2 Output: 1->2->3->4->5->Null
Input: 1->2->3->4. Output: False
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def print_list(self):
temp = self.head
while(temp):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("Null")
def push(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def detect_and_remove_loop(self):
# If only 0 nodes or 1 node and that too has no self.loop then cycle doesn’t exist.
if(self.head is None or self.head.next is None):
print("Cycle doesn't exist!")
return
# Initialize fast and slow pointers
slow_ptr = fast_ptr = self.head
slow_ptr = slow_ptr.next
fast_ptr = fast_ptr.next.next
# Detecting the Loop
while(slow_ptr and fast_ptr and fast_ptr.next):
if(slow_ptr == fast_ptr):
# Loop detected start removing the loop using fast_ptr and slow_ptr at same speed
# and starting slow_ptr from head and fast_ptr from meet point
slow_ptr = self.head
while(slow_ptr.next != fast_ptr.next):
slow_ptr = slow_ptr.next
fast_ptr = fast_ptr.next
print("Cycle exists from Node-{} to Node-{}!".format(fast_ptr.data, fast_ptr.next.data))
# Make next of fast_ptr None to break loop
fast_ptr.next = None
return
slow_ptr = slow_ptr.next
fast_ptr = fast_ptr.next.next
# If reaches here mean cycle not exists
print("Cycle doesn't exist!")
print("Detect and Remove Loop Example-1:")
linked_list = LinkedList()
linked_list.head = Node(1)
linked_list.head.next = Node(2)
linked_list.head.next.next = Node(3)
linked_list.head.next.next.next = Node(4)
linked_list.head.next.next.next.next = Node(5)
#Create a loop for testing
linked_list.head.next.next.next.next.next = linked_list.head.next
linked_list.detect_and_remove_loop()
print ("After removing loop:")
linked_list.print_list()
print("\nDetect and Remove Loop Example-2:")
linked_list = LinkedList()
linked_list.push(5)
linked_list.push(3)
linked_list.push(6)
linked_list.push(7)
linked_list.push(4)
linked_list.detect_and_remove_loop()
Output:
Note: The problem can also be solved in O(n) using hashing the visited node address but it will take O(N) space.
Insert a node in circular linked list.
Example:
Input: 1->2->3->4->5->1 num=6 Output: 6->1->2->3->4->5->6
class Node:
def __init__(self, data):
self.data = data
self.next = None
class CircularLinkedList:
def __init__(self):
self.head = None
def push(self, data):
current_node = self.head
new_node = Node(data)
#### Case-1: If this is first node being inserted make the self loop.
if current_node is None:
# (1) Make the next of new_node point to new_node itself (self-loop).
new_node.next = new_node
# (2) Point the head to new_node.
self.head = new_node
#### Case-2: Insert at starting before head.
else:
# (1) Make the next of new_node point to where head was pointing earlier.
new_node.next = self.head
# (2) Find the last node and make last_node's next point to new_node.
last_node = self.head
while(last_node.next != self.head):
last_node = last_node.next
last_node.next = new_node
# (3) Point the head to new_node.
self.head = new_node
def print_list(self):
temp = self.head
while(temp.next != self.head):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("{}-->{}".format(temp.data, temp.next.data))
print("Original Circular Linked List:")
cll = CircularLinkedList()
cll.push(5)
cll.push(4)
cll.push(3)
cll.push(2)
cll.push(1)
cll.print_list()
print("\nCircular Linked List After Insertion of 6:")
cll.push(6)
cll.print_list()
Output:
Split a circular linked list into 2 circular list of equal sizes.
If there are odd number of nodes, then first list should contain one extra.
class Node:
def __init__(self, data):
self.data = data
self.next = None
class CircularLinkedList:
def __init__(self):
self.head = None
def push(self, data):
new_node = Node(data)
# new_node's next will point to the previous_first_node which head was pointing earlier
new_node.next = self.head
# Only 1 node : self loop
if self.head is None:
new_node.next = new_node
else:
# last_node's next will point to new_node
last_node = self.head
while(last_node.next != self.head):
last_node = last_node.next
last_node.next = new_node
# Now the head will point to new_node
self.head = new_node
def print_list(self):
temp = self.head
while(temp.next != self.head):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("{}".format(temp.data))
def split_into_halves(self, second_cll):
if(self.head is None):
return
fast_ptr = slow_ptr = self.head
# If Odd no. of nodes in then fast_ptr->next becomes head and
# if Even no. of nodes fast_ptr->next->next becomes head
while(fast_ptr.next!=self.head and fast_ptr.next.next!=self.head):
fast_ptr = fast_ptr.next.next
slow_ptr = slow_ptr.next
#======== Making 2nd half circular ========#
# Start of 2nd half: slow_ptr.next
# End of 2nd half : fast_ptr (Odd no. of nodes) || fast_ptr.next (Even no. of nodes)
if fast_ptr.next.next == self.head:
fast_ptr = fast_ptr.next
second_cll.head = slow_ptr.next
fast_ptr.next = slow_ptr.next
#======== Making 1st half circular ========#
# Start of 1st half: head (self.head = self.head)
# End of 1st half : slow_ptr)
slow_ptr.next = self.head
print("Example-1(Odd Nodes): Original Circular Linked List:")
cll = CircularLinkedList()
cll.push(5)
cll.push(4)
cll.push(3)
cll.push(2)
cll.push(1)
cll.print_list()
print("Circular Linked List after Splitting:")
second_cll = CircularLinkedList()
cll.split_into_halves(second_cll)
cll.print_list()
second_cll.print_list()
print("\nExample-2(Even Nodes): Original Circular Linked List:")
cll = CircularLinkedList()
cll.push(6)
cll.push(5)
cll.push(4)
cll.push(3)
cll.push(2)
cll.push(1)
cll.print_list()
print("Circular Linked List after Splitting")
second_cll = CircularLinkedList()
cll.split_into_halves(second_cll)
cll.print_list()
second_cll.print_list()
Output:
Write a function to insert a new value in a sorted Circular Linked List.
Examples:
Input: 2->4->7->8->2
Insert: 1 Output: 1-2->4->7->8->1 (At beginning)
Insert: 5 Output: 1->2->4->5->7->8->1 (In between)
Input: 9 Output: 1->2->4->5->7–>8->9->1 (At last)
class Node:
def __init__(self, data):
self.data = data
self.next = None
class CircularLinkedList:
def __init__(self):
self.head = None
def sorted_insert(self, data):
current_node = self.head
new_node = Node(data)
#### Case-1: If this is first node being inserted make the self loop.
if current_node is None:
# (1) Make the next of new_node point to new_node itself (self-loop).
new_node.next = new_node
# (2) Point the head to new_node.
self.head = new_node
#### Case-2: Insert at starting before head.
elif(data <= current_node.data):
# (1) Make the next of new_node point to where head was pointing earlier.
new_node.next = self.head
# (2) Find the last node and make last_node's next point to new_node.
last_node = self.head
while(last_node.next != self.head):
last_node = last_node.next
last_node.next = new_node
# (3) Point the head to new_node.
self.head = new_node
#### Case-3: Insert by searching (linear search) the appropriate place to insert.
else:
while( current_node.next != self.head and data > current_node.next.data):
current_node = current_node.next
# (1) Make the next of new_node point to where current was pointing earlier (current.next).
new_node.next = current_node.next
# (2) Make the next of current_node point to new_node.
current_node.next = new_node
def print_list(self):
temp = self.head
while(temp.next != self.head):
print("{}-->".format(temp.data), end="")
temp = temp.next
print("{}-->{}".format(temp.data, temp.next.data))
print("Original Circular Linked List:")
cll = CircularLinkedList()
cll.sorted_insert(4)
cll.sorted_insert(2)
cll.sorted_insert(8)
cll.sorted_insert(7)
cll.print_list()
print("\nInsertion at Beginning (1):")
cll.sorted_insert(1)
cll.print_list()
print("\nInsertion in Between (5):")
cll.sorted_insert(5)
cll.print_list()
print("\nInsertion at Last(9):")
cll.sorted_insert(9)
cll.print_list()
Output: