Delete a node in a linked list recursively - python

The below code deletes a node in a linked list using iteration.
Now I would like to to delete a node using recursion:
def delete(self, key):
temp = self.head
if (temp is not None):
if temp.data == key:
self.head = temp.next
temp = None
return
if temp is None:
return
while (temp is not None):
if temp.data == key:
break
prev = temp
temp = temp.next
prev.next = temp.next
temp = None
I don't see how I can make this recursive...

def deleteNode(root, key):
if not root:
return None
if root.data == key: # delete the first node of linked list
return root.next
if root.next:
next = deleteNode(root.next, key)
root.next = next
return root

Here I have attempted to correct it. You need to assign prev before break as break will exit from the loop and your prev and temp will never be assigned in some cases.
def delete(self,key):
temp=self.head
if(temp is not None):
if temp.data==key:
self.head=temp.next
temp=None
return
if temp is None:
return
while(temp is not None):
prev=temp
temp=temp.next
if temp.data==key:
break
prev.next=temp.next
temp=None

First of all, your code will run into an exception when the data is not found in the list. Secondly, it is not necessary to do temp = None just before exiting the function.
To cope with the first issue, the iterative function could be:
def deleteNode(self, key):
prev = None
node = self.head
while node and node.data != key:
prev = node
node = node.next
if node == self.head:
self.head = node.next
elif node:
prev.next = node.next
The recursive version:
def deleteNode(self, key):
def recur(node):
if node:
if node.data == key:
return node.next
node.next = recur(node.next)
return node
self.head = recur(self.head)

Considering singly linked list of integers and position(pos) 'i'.
Deleting the node present at the 'i-th' position
def deleteNodeRec(head, pos) :
#Your code goes here
if pos == 0:
return head.next
if (head.next is None):
return head
head.next = deleteNodeRec(head.next,pos-1)
return head
Reference: https://www.svastikkka.com/2022/07/delete-node-recursive.html

Related

Delete last node in linked list

I am implementing deletion of last node in linked list using Python. Below is my code:
class Node:
def __init__(self, key):
self.key = key
self.next = None
def printList(head):
curr = head
while curr != None:
print(curr.key, end=" ")
curr = curr.next
def deleteLastNode(head):
if head == None:
return None
temp = head
# Iterating till the last Node
while temp.next != None:
temp = temp.next
temp = None
return head
# Driver code
head = Node(10)
head.next = Node(20)
head.next.next = Node(30)
head = deleteLastNode(head)
printList(head)
However, in output I'm still getting the complete linked list.
10 20 30
How is it printing 30 when the last node is already set to temp = None?
Well, your linked list is:
10 -> 20 -> 30
^head
Your iteration:
10 -> 20 -> 30
^head ^temp
Then when you do temp = None, just means(you just assign None to temp):
10 -> 20 -> 30 None
^head ^temp
A correct way is when you iterate on 20, do temp.next = None to remove the reference to the last node. So your code might be:
class Node:
def __init__(self, key):
self.key = key
self.next = None
def printList(head):
curr = head
while curr != None:
print(curr.key, end=" ")
curr = curr.next
def deleteLastNode(head):
if head == None:
return None
temp = head
# Iterating till the last Node
while temp.next.next != None:
temp = temp.next
temp.next = None
return head
# Driver code
head = Node(10)
head.next = Node(20)
head.next.next = Node(30)
head = deleteLastNode(head)
printList(head)
This code would work when your linked list contain at least two elements. When there is only one element, this will raise exception. I would recommend you use a dummy head node which next point to the real head node.
#Another way of solving
class Node:
def __init__(self, key):
self.key = key
self.next = None
def printList(head):
curr = head
while curr != None:
print(curr.key, end=" ")
curr = curr.next
def deleteLastNode(head):
if head == None:
return None
temp = head
prev=None #creating the value of previous element
# Iterating till the last Node
while temp.next != None:
prev=temp #updating for every iteration
temp = temp.next
prev.next = None #returning as NONE value
return head
# Driver code
head = Node(10)
head.next = Node(20)
head.next.next = Node(30)
head = deleteLastNode(head)
printList(head)

Remove Duplicates from unsorted Linked list(python)

In my last code for removing duplicates, the method removeDup isn't working.
The last print(ll.display()) is printing the previous linked list.
I was hoping it to print only unique nodes. What am I missing in removeDups method?
I can't figure out. What is happening in the code here?
class Node:
def __init__(self,data = None):
self.data = data
self.next = None
def __repr__(self):
return self.data
class LList:
def __init__(self):
self.head = None
def display(self):
current = self.head
node = []
while current != None:
node.append(current.data)
current = current.next
return node
def append(self, data):
elem = Node(data)
if self.head == None:
self.head = elem
else:
current = self.head
while current.next != None:
current = current.next
current.next = elem
def add_atFront(self, data):
elem = Node(data)
if self.head == None:
self.head = elem
else:
elem.next = self.head
self.head = elem
def removeDup(self):
current = self.head
previous = None
elems = []
while current != None:
if current.data in elems:
previous.next= current.next
else:
elems.append(current.data)
previous = current
current = current.next
ll= LList()
print(ll.display())
ll.append(65)
ll.append(7)
ll.add_atFront('65')
ll.add_atFront('Bare')
ll.insert('10',0)
ll.insert('7',2)
print(ll.display())
ll.removeDup()
print(ll.display())
Your removeDup works fine, the issue is that 65 and '65' are not duplicates, so you should not expect removeDup to dedup them. The same goes for 7 and '7'. Also, note you never defined the insert method, but I'll assume that's just a copy error.

Merging 2 Linkedlists in python NOT working. Third Linked List created is giving me a NULL value/result after execution

I'm currently stuck on this python exercise where I have 2 LinkedLists (linked_list_1,linked_list_2) which I have to merge together in a new LinkedList. I have tried this code but it keeps giving me a null value for the third LinkedList when I need it to give me the data in both linkedLists. The function is called: merge_linked_lists(linked_list_1, linked_list_2). That's where my problem is. I would be really grateful if someone can help.
class Node:
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def __str__(self):
return str(self.data)
class LinkedList:
def __init__(self):
self.length = 0
self.head = None
def print_list(self):
node = self.head
while node is not None:
print(node, end=' ')
node = node.next
print('')
def add_at_head(self, node):
node.next = self.head
self.head = node
self.length += 1
def remove_node_after(self, node):
if node.next is not None:
temp = node.next
node.next = node.next.next
temp.next = None
self.length -= 1
def remove_first_node(self):
if self.head is None:
return
temp = self.head
self.head = self.head.next
temp.next = None
self.length -= 1
def print_backward(self):
def print_nodes_backward(node):
if node.next is not None:
print_nodes_backward(node.next)
if node is not None:
print(node, end=' ')
if self.head is not None:
print_nodes_backward(self.head)
print('')
def merge_linked_lists(linked_list_1, linked_list_2):
def merge(List_1, List_2):
head_ptr = temp_ptr = Node() # head_ptr will be the head node of the output list
# temp_ptr will be used to insert nodes in the output list
# Loop for merging two lists
# Loop terminates when both lists reaches to its end
while List_1 or List_2:
# List_1 has not reached its end
# and List_2 has either reached its end or its current node has data
# greater than or equal to the data of List_1 node
# than insert List_1 node in the ouput list
if List_1 and (not List_2 or List_1.data <= List_2.data):
temp_ptr.next = Node(List_1.data)
List_1 = List_1.next
# otherwise insert List_2 node in the ouput list
else:
temp_ptr.next = Node(List_2.data)
List_2 = List_2.next
# move temp_pointer to next position
temp_ptr = temp_ptr.next
# return output list
return head_ptr.next
merge(linked_list_1.head, linked_list_2.head)
# Test merge() function
LL1 = LinkedList()
LL1.add_at_head(Node(2))
LL1.add_at_head(Node(4))
LL1.add_at_head(Node(6))
LL1.add_at_head(Node(8))
LL2 = LinkedList()
LL2.add_at_head(Node(1))
LL2.add_at_head(Node(3))
LL2.add_at_head(Node(5))
LL2.add_at_head(Node(7))
# Merge Function
LL3 = LinkedList()
LL3.head = merge_linked_lists(LL1, LL2)
LL3.print_list()
EDIT 1:
To anyone who wants to know the output, I tried this code on my IDE (Pycharm) and it gave an empty output/result. I also tried it on pythontutor (It visuals i/o there) and I saw that linked_list_1 and linked_list_2 haven't changed but the third linked list was null. Also during the execution, the third linkedlist was able to merge them together but it had an extra node which was the first node (head) and it had NONE as data.
EDIT 2:
The code finally worked!
class Node:
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def __str__(self):
return str(self.data)
class LinkedList:
def __init__(self):
self.length = 0
self.head = None
def print_list(self):
node = self.head
while node is not None:
print(node, end=' ')
node = node.next
print('')
def add_at_head(self, node):
node.next = self.head
self.head = node
self.length += 1
def remove_node_after(self, node):
if node.next is not None:
temp = node.next
node.next = node.next.next
temp.next = None
self.length -= 1
def remove_first_node(self):
if self.head is None:
return
temp = self.head
self.head = self.head.next
temp.next = None
self.length -= 1
def print_backward(self):
def print_nodes_backward(node):
if node.next is not None:
print_nodes_backward(node.next)
if node is not None:
print(node, end=' ')
if self.head is not None:
print_nodes_backward(self.head)
print('')
def sortList(self):
#Node current will point to head
current = self.head;
index = None;
if(self.head == None):
return;
else:
while(current != None):
#Node index will point to node next to current
index = current.next;
while(index != None):
#If current node's data is greater than index's node data, swap the data between them
if(current.data > index.data):
temp = current.data;
current.data = index.data;
index.data = temp;
index = index.next;
current = current.next;
def merge_linked_lists(linked_list_1, linked_list_2):
linked_list_1.sortList()
linked_list_2.sortList()
def merge(List_1, List_2):
head_ptr = temp_ptr = Node() # head_ptr will be the head node of the output list
# temp_ptr will be used to insert nodes in the output list
# Loop for merging two lists
# Loop terminates when both lists reaches to its end
while List_1 or List_2:
# List_1 has not reached its end
# and List_2 has either reached its end or its current node has data
# greater than or equal to the data of List_1 node
# than insert List_1 node in the ouput list
if List_1 and (not List_2 or List_2.data >= List_1.data):
temp_ptr.next = Node(List_1.data)
List_1 = List_1.next
# otherwise insert List_2 node in the ouput list
else:
temp_ptr.next = Node(List_2.data)
List_2 = List_2.next
# move temp_pointer to next position
temp_ptr = temp_ptr.next
# return output list
return head_ptr.next
return merge(linked_list_1.head, linked_list_2.head)
# Test merge() function
LL1 = LinkedList()
LL1.add_at_head(Node(2))
LL1.add_at_head(Node(4))
LL1.add_at_head(Node(6))
LL1.add_at_head(Node(8))
LL2 = LinkedList()
LL2.add_at_head(Node(1))
LL2.add_at_head(Node(3))
LL2.add_at_head(Node(5))
LL2.add_at_head(Node(7))
# Merge Function
LL3 = LinkedList()
LL3.head = merge_linked_lists(LL1, LL2)
LL3.print_list()
Ps: I also made another code which also worked.
class Node:
def __init__(self, data=None, next_node=None):
self.data = data
self.next = next_node
def __str__(self):
return str(self.data)
class LinkedList:
def __init__(self):
self.length = 0
self.head = None
def sortList(self):
# Node current will point to head
current = self.head;
index = None;
if (self.head == None):
return;
else:
while (current != None):
# Node index will point to node next to current
index = current.next;
while (index != None):
# If current node's data is greater than index's node data, swap the data between them
if (current.data < index.data):
temp = current.data;
current.data = index.data;
index.data = temp;
index = index.next;
current = current.next;
def print_list(self):
node = self.head
while node is not None:
print(node, end=' ')
node = node.next
print('')
def add_at_head(self, node):
node.next = self.head
self.head = node
self.length += 1
def remove_node_after(self, node):
if node.next is not None:
temp = node.next
node.next = node.next.next
temp.next = None
self.length -= 1
def remove_first_node(self):
if self.head is None:
return
temp = self.head
self.head = self.head.next
temp.next = None
self.length -= 1
def print_backward(self):
def print_nodes_backward(node):
if node.next is not None:
print_nodes_backward(node.next)
if node is not None:
print(node, end=' ')
if self.head is not None:
print_nodes_backward(self.head)
print('')
def merge_linked_lists(linked_list_1, linked_list_2):
linked_list_1.sortList()
linked_list_2.sortList()
LL3 = LinkedList()
node = linked_list_2.head
node1 = linked_list_1.head
if node is None and node1 is None:
return LL3
while True:
if node1 is None:
LL3.add_at_head(Node(node.data))
node = node.next
if node is None:
return LL3
else:
continue
if node is None:
LL3.add_at_head(Node(node1.data))
node1 = node1.next
if node1 is None:
return LL3
else:
continue
if node.data > node1.data:
LL3.add_at_head(Node(node.data))
node = node.next
if node1.data > node.data:
LL3.add_at_head(Node(node1.data))
node1 = node1.next
return LL3
# Test merge() function
# Linked List with even numbers
LL1 = LinkedList()
LL1.add_at_head(Node(2))
LL1.add_at_head(Node(4))
LL1.add_at_head(Node(6))
LL1.add_at_head(Node(8))
# Linked List with odd numbers
LL2 = LinkedList()
LL2.add_at_head(Node(1))
LL2.add_at_head(Node(3))
LL2.add_at_head(Node(5))
LL2.add_at_head(Node(7))
# Merge Function
LL3 = LinkedList()
LL3 = merge_linked_lists(LL1, LL2)
LL3.print_list()
Your merge function has no return statement:
Change:
merge(linked_list_1.head, linked_list_2.head)
to:
return merge(linked_list_1.head, linked_list_2.head)
Another issue is that the sort order of your two input lists is descending, while your merge function assumes they are sorted ascending. So as a result your merged list is not sorted.
So either initialise your lists to be ascending in order (remember you insert values in reversed order) or change <= to >= in your merge function.

LinkedList delete functionality is deleting 2 nodes

I'm creating my own linkedList implementation and am somehow deleting 2 nodes at once. I do not understand why. I have tried deleting different integers and it seems to really like to delete the second entry in the list.
When I don't use the delete method the list traverses correctly. This leads me to believe that I am deleting incorrectly. I am keeping track of the previous node with the place_node various.
class LinkedList:
def __init__(self):
self.head = None
def prepend(self,data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def traversal(self):
temp = self.head
while temp is not None:
print(temp.data)
temp = temp.next
def append(self,data):
new_node = Node(data)
place_node = None
temp = self.head
while temp is not None:
place_node = temp
temp = temp.next
new_node.next = place_node.next
place_node.next = new_node
def delete(self,data):
new_node = Node(data)
temp = self.head
while temp is not None:
if temp.data == data:
break
place_node = temp
temp = temp.next
place_node.next = temp.next
class Node:
def __init__(self,data):
self.data = data
self.next = None
ehren = LinkedList()
ehren.prepend(5)
ehren.prepend(3)
ehren.prepend(8)
ehren.append(6)
print(" delete the number")
ehren.delete(6)
print("linked list***********")
ehren.traversal()
The delete method should be implemented like this:
def delete(self, data):
prev = None
temp = self.head
while temp is not None:
if temp.data == data:
if prev is None: # Handle the case when we are deleting the head which has no previous node
self.head = self.head.next
else:
prev.next = temp.next
break
prev = temp
temp = temp.next
Since this is a singly-linked-list, you need to keep track of the node before the target, and to delete means to set the next pointer of the previous node to the next pointer of the node to be deleted, thus making the selected node disappear.

Linked List in Python- Append, Index, Insert, and Pop functions. Not sure with code/errors

This assignment asks us to implement the append, insert, index and pop methods for an unordered linked-list.
(What I have so far)
def main():
class Node:
def __init__(self, data):
self.data = data
self.next_node = None
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def AppendNode(self, data):
new_node = Node(data)
if self.head == None:
self.head = new_node
if self.tail != None:
self.tail.next = new_node
self.tail = new_node
def PrintList( self ):
node = self.head
while node != None:
print (node.data)
node = node.next
def PopNode( self, index ):
prev = None
node = self.head
i = 0
while ( node != None ) and ( i < index ):
prev = node
node = node.next
i += 1
if prev == None:
self.head = node.next
else:
prev.next = node.next
list = LinkedList()
list.AppendNode(1)
list.AppendNode(2)
list.AppendNode(3)
list.AppendNode(4)
list.PopNode(0)
list.PrintList( )
The output so far:
2
3
4
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
main()
File "<pyshell#31>", line 50, in main
list.PrintList( )
File "<pyshell#31>", line 27, in PrintList
node = node.next
AttributeError: 'Node' object has no attribute 'next'
I'm not sure why i'm getting the errors, since the code is technically working. Also any input on the insert, and index functions would be greatly appreciated.
For insert and index methods you will need another Node attribute, because you'll need to keep track of which item is on what position. Let we call it position. Your Node class will now look like this:
class Node:
def __init__(self, data, position = 0):
self.data = data
self.next_node = None
self.position = position
Retrieving index value now is easy as:
def index(self,item):
current = self.head
while current != None:
if current.data == item:
return current.position
else:
current = current.next
print ("item not present in list")
As for the list-altering methods, I would start with a simple add method which adds items to the leftmost position in the list:
def add(self,item):
temp = Node(item) #create a new node with the `item` value
temp.next = self.head #putting this new node as the first (leftmost) item in a list is a two-step process. First step is to point the new node to the old first (lefmost) value
self.head = temp #and second is to set `LinkedList` `head` attribute to point at the new node. Done!
current = self.head #now we need to correct position values of all items. We start by assigning `current` to the head of the list
self.index_correct(current) #and we'll write helper `index_correct` method to do the actual work.
current = self.head
previous = None
while current.position != self.size() - 1:
previous = current
current = current.next
current.back = previous
self.tail = current
What shall the index_correct method do? Just one thing - to traverse the list in order to correct index position of items, when we add new items (for example: add, insert etc.), or remove them (remove, pop, etc.). So here's what it should look like:
def index_correct(self, value):
position = 0
while value != None:
value.position = position
position += 1
value = value.next
It is plain simple. Now, let's implement insert method, as you requested:
def insert(self,item,position):
if position == 0:
self.add(item)
elif position > self.size():
print("position index out of range")
elif position == self.size():
self.AppendNode(item)
else:
temp = Node(item, position)
current = self.head
previous = None
while current.position != position:
previous = current
current = current.next
previous.next = temp
temp.next = current
temp.back = previous
current.back = temp
current = self.head
self.index_correct(current)
Below is the implementation that I could come up with (tested and working). It seems to be an old post, but I couldn't find the complete solution for this anywhere, so posting it here.
# add -- O(1)
# size -- O(1) & O(n)
# append -- O(1) & O(n)
# search -- O(n)
# remove -- O(n)
# index -- O(n)
# insert -- O(n)
# pop -- O(n) # can be O(1) if we use doubly linked list
# pop(k) -- O(k)
class Node:
def __init__(self, initdata):
self.data = initdata
self.next = None
def getData(self):
return self.data
def getNext(self):
return self.next
def setNext(self, newnext):
self.next = newnext
class UnorderedList:
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def isEmpty(self):
return self.head is None
def add(self, item):
temp = Node(item)
temp.setNext(self.head)
self.head = temp
if self.tail is None:
self.tail = temp
self.length += 1
def ssize(self): # This is O(n)
current = self.head
count = 0
while current is not None:
count += 1
current = current.getNext()
return count
def size(self): # This is O(1)
return self.length
def search(self, item):
current = self.head
found = False
while current is not None and not found:
if current.getData() == item:
found = True
else:
current = current.getNext()
return found
def remove(self,item):
current = self.head
previous = None
found = False
while current is not None and not found:
if current.getData() == item:
found = True
else:
previous = current
current = current.getNext()
if previous == None:
# The item is the 1st item
self.head = current.getNext()
else:
if current.getNext() is None:
self.tail = previous # in case the current tail is removed
previous.setNext(current.getNext())
self.length -= 1
def __str__(self):
current = self.head
string = '['
while current is not None:
string += str(current.getData())
if current.getNext() is not None:
string += ', '
current = current.getNext()
string += ']'
return string
def sappend(self, item): # This is O(n) time complexity
current = self.head
if current:
while current.getNext() is not None:
current = current.getNext()
current.setNext(Node(item))
else:
self.head = Node(item)
def append(self, item): # This is O(1) time complexity
temp = Node(item)
last = self.tail
if last:
last.setNext(temp)
else:
self.head = temp
self.tail = temp
self.length += 1
def insert(self, index, item):
temp = Node(item)
current = self.head
previous = None
count = 0
found = False
if index > self.length-1:
raise IndexError('List Index Out Of Range')
while current is not None and not found:
if count == index:
found = True
else:
previous = current
current = current.getNext()
count += 1
if previous is None:
temp.setNext(self.head)
self.head = temp
else:
temp.setNext(current)
previous.setNext(temp)
self.length += 1
def index(self, item):
pos = 0
current = self.head
found = False
while current is not None and not found:
if current.getData() == item:
found = True
else:
current = current.getNext()
pos += 1
if not found:
raise ValueError('Value not present in the List')
return pos
def pop(self, index=None):
if index is None:
index = self.length-1
if index > self.length-1:
raise IndexError('List Index Out Of Range')
current = self.head
previous = None
found = False
if current:
count = 0
while current.getNext() is not None and not found:
if count == index:
found = True
else:
previous = current
current = current.getNext()
count += 1
if previous is None:
self.head = current.getNext()
if current.getNext() is None:
self.tail = current.getNext()
else:
self.tail = previous
previous.setNext(current.getNext())
self.length -= 1
return current.getData()
def insert(self,item,position):
if position==0:
self.add(item)
elif position>self.size():
print("Position index is out of range")
elif position==self.size():
self.append(item)
else:
temp=Node.Node(item,position)
current=self.head
previous=None
current_position=0
while current_position!=position:
previous=current
current=current.next
current_position+=1
previous.next=temp
temp.next=current
Notice that in the Node class you defined the "next" field as "next_node". Therefore the interpreter doesn't know "next". So, instead of node.next it should be node.next_node

Categories

Resources