How do I remove node in Linked List? - python

I am implementing Linked List by using Python. Here is my code
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self, head = None):
self.head = head
def append(self, newElement):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = newElement
else:
self.head = newElement
#get position time complexity O(n)
#get the node at a specific position
def get_position(self, position):
current = self.head
current_pos = 1
while current_pos <= position:
if current_pos == position:
return current
current = current.next
current_pos += 1
return None
#Insert element
# Time complexity O(n)
def insert_element(self, element, position):
if position > 1:
front_pos = self.get_position(position - 1)
end_pos = self.get_position(position + 1)
front_pos.next = element
element.next = end_pos
else:
element.next = self.head
self.head = element
def delete_element(self, element):
current = self.head
previous = None
while current:
if current.value == element:
if not previous:
self.head = element
previous.next = current.next
else:
current = current.next
previous = current
else:
return False
node1 = Node("Iron Man")
node2 = Node("Capitain America")
node3 = Node("Doctor Strange")
node4 = Node("Spider man")
node5 = Node("Rieder")
print("Node1 Value is {}".format(node1.value))
print("Node1 next Value is {}".format(node1.next))
print("Node2 Value is {}".format(node2.value))
print("Node2 next Value is {}".format(node2.next))
Avengers = LinkedList()
Avengers.append(node1)
print("Firt element in link list is {}".format(Avengers.head.value))
Avengers.append(node2)
print("After Iron Man is {}".format(Avengers.head.next.value))
print(Avengers.get_position(2).value)
Avengers.append(node3)
Avengers.append(node4)
Avengers.insert_element(node5, 4)
print(Avengers.get_position(4).value)
Avengers.delete_element(node5)
print(Avengers.get_position(4).value)
Here is my output:
Node1 Value is Iron Man
Node1 next Value is None
Node2 Value is Capitain America
Node2 next Value is None
Firt element in link list is Iron Man
After Iron Man is Capitain America
Capitain America
Rieder
Rieder
The list structure link like this: Ironman -> Capitain America -> Doctor Strange -> Rieder -> Spiderman
Therefore, if I do not want the "Rieder" node. The last line of output should show "Spider man"
What happened in my code? Really appreciate for people who help me out :D

One issue is that you appear to update current and then update previous with the new value of current. I would go back to your delete method, and go through it line by line. It helps if you write out on paper what the state of your list is at each line, and see if you can correct the algorithm.
else:
current = current.next
previous = current

First you need to fix your insert_element function. You are inserting nodes incorrectly. This is the correct way to do it
def insert_element(self, element, position):
if position > 1:
front_pos = self.get_position(position - 1)
# end_pos should not be position + 1, because it will
# skip the element at index=position
end_pos = self.get_position(position)
front_pos.next = element
element.next = end_pos
else:
element.next = self.head
self.head = element
Next, you need to only pass the value of the nodes and not the nodes themselves while deleting the elements. I have made some minor changes to your code to fix some bugs. See the comments for more information
def delete_element(self, element):
current = self.head
previous = None
while current:
if current.value == element:
# This means that the head itself
# has to be deleted
if not previous:
self.head = self.head.next
# Add an else block correctly here
# in case head is not to be deleted
else:
previous.next = current.next
# break the loop when the element is deleted
break
else:
# First copy the current into previous,
# Then change the value of current
previous = current
current = current.next
Also there is no need for else: return False block at the end of delete function.

Related

How to make a delete function for a Linked-List in Python

I am ongoing an online course which includes actions with linked lists in Python. The exercise is to make get_position, insert and delete actions for a linked list class and then get the required results commented at the bottom of the script. I have been stuck on the delete function for the past few days and I can't see the (maybe obvious) solution.
My code looks like this:
"""The LinkedList code from before is provided below.
Add three functions to the LinkedList.
"get_position" returns the element at a certain position.
The "insert" function will add an element to a particular
spot in the list.
"delete" will delete the first element with that
particular value.
Then, use "Test Run" and "Submit" to run the test cases
at the bottom."""
class Element(object):
def __init__(self, value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def append(self, new_element):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new_element
else:
self.head = new_element
def get_position(self, position):
"""Get an element from a particular position.
Assume the first position is "1".
Return "None" if position is not in the list."""
current = self.head
i = 1
if self.head:
while i < position:
current = current.next
i = i + 1
return current
else:
return None
def insert(self, new_element, position):
"""Insert a new node at the given position.
Assume the first position is "1".
Inserting at position 3 means between
the 2nd and 3rd elements."""
current = self.head
i = 1
if self.head:
while i < position - 1:
current = current.next
i = i + 1
current.next = new_element
while current.next:
current = current.next
else:
self.head = new_element
pass
def delete(self, value):
"""Delete the first node with a given value."""
if self.head is None:
raise Exception("List is empty")
if self.head.value == value:
self.head = self.head.next
current = self.head
i = 1
while current.next:
current = current.next
return
previous = self.head
for element in self:
if element.value == value:
previous.next = element.next
return
previous = element
# Test cases
# Set up some Elements
e1 = Element(1)
e2 = Element(2)
e3 = Element(3)
e4 = Element(4)
# Start setting up a LinkedList
ll = LinkedList(e1)
ll.append(e2)
ll.append(e3)
# Test get_position
# Should print 3
print ll.head.next.next.value
# Should also print 3
print ll.get_position(3).value
# Test insert
ll.insert(e4,3)
# Should print 4 now
print ll.get_position(3).value
# Test delete
ll.delete(1)
# Should print 2 now
print ll.get_position(1).value
# Should print 4 now
print ll.get_position(2).value
# Should print 3 now
print ll.get_position(3).value
The only value I can't get is the last one and this is the error screen:
Traceback (most recent call last):
File "vm_main.py", line 31, in <module>
import main
File "/tmp/workspaces/04497b9c-ee1c-47bc-9e15-b58ef0e5580c/main.py", line 2, in <module>
import studentMain
File "/tmp/workspaces/04497b9c-ee1c-47bc-9e15-b58ef0e5580c/studentMain.py", line 2, in <module>
import algorithmsP2
File "/tmp/workspaces/04497b9c-ee1c-47bc-9e15-b58ef0e5580c/algorithmsP2.py", line 112, in <module>
print ll.get_position(3).value
AttributeError: 'NoneType' object has no attribute 'value'
Edit:
I found the fix. It was the insert method acting up so I changed it to
def insert(self, new_element, position):
"""Insert a new node at the given position.
Assume the first position is "1".
Inserting at position 3 means between
the 2nd and 3rd elements."""
current = self.head
i = 1
if self.head:
while i < position - 1:
current = current.next
i = i + 1
that = current.next
new_element.next = that
current.next = new_element
while current.next:
current = current.next
else:
self.head = new_element

Inserting and getting the position in a Linked List class using python

I am new to Data Structure and algorithms. I'm a self-taught Python programmer. I am doing a course on it and I wanted to make a linked list, get a specific position in the linked list, insert, and delete an element in the list.
So I wrote my code, and to me, it seems fine. It's not giving me any errors, but it's not executing as well.
This is the code that I wrote,
class Element(object):
def __init__(self, value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def append(self, new_element):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new_element
else:
self.head = new_element
def get_position(self, position):
"""Get an element from a particular position.
Assume the first position is "1".
Return "None" if position is not in the list."""
current = self.head
if self.head:
while current.next:
if current == position:
return current
else:
continue
else:
return None
def insert(self, new_element, position):
"""Insert a new node at the given position.
Assume the first position is "1".
Inserting at position 3 means between
the 2nd and 3rd elements."""
current = self.head
if self.head:
while current.next:
if current.next == position:
current.next = new_element
break
else:
continue
else:
self.head = new_element
The error is in get position function and insert function
can anyone tell me what is it that I'm doing wrong?
Is there an issue with the loop or something?
Please help me, I'll be grateful!! Thanks.
Some issues in get_position:
current == position is not the condition you need to verify. position is a number and current is an Element, so they don't really compare. You need to verify whether the position is 1 or 2, ... depending on how far you are in your list.
The loop never advances current to the next node. So this represents an infinite loop.
The while condition should not check current.next, but current. Otherwise you will never do a check for the last node in the list.
Here is your code corrected:
def get_position(self, position):
if position < 1: # Just in case the position is too small
return
current = self.head
while current and position > 1:
position -= 1
current = current.next
return current
So the loop ends whenever position gets to be decreased to 1, or there is no more node. In the latter case the return value will be None.
Although your question is about the get_position function, your insert also has the same problems. On top of that it also treats the head case wrong. It should also change the head when the provided position is 1.
The insert method can in fact make use of the above function to find the node that should precede the node to be inserted:
def insert(self, new_element, position):
if position == 1:
new_element.next = self.head
self.head = new_element
else:
before = self.get_position(position-1)
if before is None:
raise ValueError("invalid position")
new_element.next = before.next
before.next = new_element

Find the frequency of numbers using linkedlist

Find the frequency of numbers using linkedlist.
Getting SIGTSTP - time limit exceed error while running the below code. Can anyone help me where am I getting it wrong?
class Element(object):
def __init__(self,value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head = None):
self.head = head
def append(self, new):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new
else:
self.head = new
def traverse(self):
current = self.head
while current != None:
print(current.value)
current = current.next
arr = list(map(int, input().split()))
ll = LinkedList()
for i in arr:
e = Element(i)
ll.append(e)
ll.traverse()
def frequency(a):
current = a.head
while current != None:
count = 1
while current.next != None:
if current.value == current.next.value:
current+=1
if current.next.next != None:
current.next = current.next.next
else:
current.next = None
print(str(current.value)+" : " + str(count))
current = current.next
frequency(ll)
Everything looks fine except frequency. You will need to keep two references, one to the current element and the other will traverse the remainder of the list, starting from current. Does that give you something to go on?
Note too that your current implementation will modify the underlying linked list, while you can indeed do "skipping" with the pointers to prevent listing the same element multiple times, it is imo preferable to avoid modifying the underlying structure in this way.

How do I update my self.tail in a method for deleting a node at a specific position when the position is the last node?

Method obtained from googling and changed a bit:
def removeNodeAtPosition(self, position):
if self.head == None:
print("List is empty")
return
current = self.head
if position == 0:
self.head = current.next
current = None
self.size-=1
return
for i in range(position-1):
current = current.next
if current == None:
break
if current == None:
return
if current.next == None:
return
next = current.next.next
current.next = None
current.next = next
if position == self.size: #two lines here used for updating self.tail
self.tail = current
self.size-=1
The title mostly says it: my self.tail value isn't changed when I delete the tail of my node with this method. I don't know if I've gone wrong with the placement of my two lines of code or if the code is wrong. I've left the most recent attempt intact. Any help resolving this will be appreciated.
Think of removing current.next instead of removing current. This way if current.next is the last element, then current would be the new tail

Algorithm to delete a node from the middle

I'm reading Cracking the Coding Interview and doing practice problems and I'm stuck on this one:
"Implement an algorithm to delete a node in the middle (i.e., any node but the first and the last node, not necessarily the exact middle) or a singly linked list, given only access to that node.
EXAMPLE
Input: the node from the linked list a->b->c->d->e->f
Result: nothing is returned, but the new linked list looks like a->b->d->e->f"
Here's my code :
class Node:
def __init__(self, data = None, nextnode = None):
self.data = data
self.nextnode = nextnode
def __str__(self):
return str(self.data)
class LinkedList():
def __init__(self, head = None):
self.head = head
def insert(self, data):
new_node = Node(data)
new_node.nextnode = self.head
self.head = new_node
def remove(self, data):
current = self.head
absent = True
if current == None: print('List is empty')
if current.data == data:
self.head = current.nextnode
absent = False
while current.nextnode:
if current.nextnode.data == data:
absent = False
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
else: current.nextnode = None
else: current = current.nextnode
if absent: print('Element not in list')
def size(self):
current = self.head
size = 0
while current:
current = current.nextnode
size += 1
return size
def find(self, data):
current = self.head
if current == None: print('List is empty')
search = True
while current and search:
if current.data == data:
print(current)
search = False
current = current.nextnode
if search: print('Not found')
def print_list(self):
current = self.head
while current:
print(current, end = ' ')
current = current.nextnode
print('')
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node1.nextnode = node2
node2.nextnode = node3
node3.nextnode = node4
list1 = LinkedList(node1)
list1.insert(2 ****EDITED node2 to 2 here****)
print_list(list1)
def delmid(ll, n):
current = ll.head
if current == n:
print('Can\'t delete first node')
return
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
delmid(list1, node2)
print_list(list1)
I can't figure out why it doesn't seem to think that ll.head and node2 are the same ... It does work if I get rid of the line list1.insert(node2) ...
I don't understand ...
EDIT: after reading the first sentence of the solution in the book, apparently i did it wrong anyways .... "given only access to that node" means you don't know the head of the list ... back to the drawing board ...
Because your insert method is wrong:
def insert(self, data):
new_node = Node(data)
new_node.nextnode = self.head
self.head = new_node
Your method does not insert node2 itself as a node: it creates a new node with node2 as payload (data). That is something different.
You can define a method:
def insert_node(self, node):
node.nextnode = self.head
self.head = new_node
Nevertheless this will create a loop since now node1 will be pointing to node2 and node2tonode1`. So the resulting linked list will be a rounded list with two elements, like:
node1 --> node2
^---------/
EDIT: since you solved that one. There is also a problem with your delmid method.
The main problem is that in your while loop you need to walk through the linked list, and you do not do that: current always remains the same, so:
def delmid(ll, n):
current = ll.head
if current == n:
print('Can\'t delete first node')
return
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
current = current.nextnode
Should fix that.
Insert operation
You misunderstood your own insert-implementation.
list1.insert(node2) inserts a new node with node2 as content:
def insert(self, data):
new_node = Node(data) # <== wrap node2 into another node instance
new_node.nextnode = self.head
self.head = new_node
Comparison of Nodes
The ==-operator internally works by calling the method __eq__(self, other). In your case you didn't provide and implementation for this method, so the default is used to compare by all variables, which includes nextnode. Thus two nodes can only be equal, if they are precisely the same. To get this corrected, use a custom comparison method in Node:
def __eq__(self, other):
return type(other) is Node && other.data == self.data
This __eq__-method would work by first checking that other definitely is of type Node and afterwards compare by the data stored in each instance.
Delmid
Going a bit further than the actual question:
while current.nextnode:
if current.nextnode == n:
if current.nextnode.nextnode:
current.nextnode = current.nextnode.nextnode
return
else:
print('Can\'t delete last node')
return
This loop will run infinitely, unless the list has at most a size of 1. To fix this step through the list by current = current.nextnode.
Improving Delmid
The actual purpose of this task was to get you used to another way of manipulating linked lists: swapping.
Instead of searching the entire list for the predecessor of n, you could just check that n is neither the first nor the last node, swap out the value with the value of it's consecutive node and delete the consecutive node:
def delmid(ll, n):
if ll.head == n:
print('Can\'t delete first node')
return
if n.nextnode is None:
print('Can\'t delete last node')
return
# swap values
tmp = n.data
n.data = n.nextnode.data
n.nextnode.data = tmp
# remove node
n.nextnode = n.nextnode.nextnode

Categories