To delete a node N
from a linked list, one must make the previous node's next pointer skip over N
by pointing to N
's next node in the sequence. For instance, if we have the following list and we want to delete item 1
we actually need to set the value of 0
's next
pointer to 1
's next pointer.
head
V
0 --> 1 --> 2 -->(None)
^ ^ ^
prev cur next
The traditional iterative solution is to use a while loop to iterate over the list keeping track of both the prev
and cur
pointers. The OPs posted answer does exactly this but instead uses a recursive call in place of a while loop.
If instead we used the recursive stack to keep track of the pointers as we iterate, stack frame i
's current pointer is stack frame i+1
's previous pointer. If we define remove_recursive(current, data)
to be a function that returns a pointer to the list or sublist pointed to by current after removing the first instance of data from the list, then we can perform the pointer updates as we "fall off the stack."
Our recursive definition looks like this:
Base cases:
1) Removing an item from an empty list
Can't do it. Return the empty list (None)
2) Remove the item from the front of the list
The sub-list with the first item removed is simply the sub-list pointed to by the next pointer. Return the next pointer. (If duplicate items are allowed and you want to delete all duplicate items, then continue recurse here -- see next step)
Recursive case:
Delete the item from the sublist pointed to by the next pointer. This is the definition of remove_recursive
with current.next
passed to it. Set current.next
to the return value of remove_recursive(current.next, data)
and return current
.
Here is my code -- which is the recursive solution in the more traditional form
def remove_recursive(self, cur, data):
if cur == None:
return None
elif cur.get_data() == data:
return cur.get_next() # removes only the first instance of data
else:
cur.set_next(self.remove_recursive(cur.get_next(), data))
return cur
def remove(self, data):
self.__head = self.remove_recursive(self.__head, data)
An observation. This recursive method uses O(N) memory in worst case as it uses the stack to store all the previous pointers. The iterative while loop method only uses O(1) extra memory because it only needs to keep track of one previous pointer. The OPs answer is actually tail recursive and in theory would have O(1) memory -- except as I understand it, python does not optimize for tail recursion.