Python : I am not able to prepend a Value in a Singly Linked list
Question:
Code written in python:
prepend Function is supposed to add a value to the start of the Linked List
display Function is supposed to display the linked list in a List format in python
fromarr Function is supposed to add new nodes to the linked list
class Node:
def __init__(self,value=None):
self.value = value
self.next = None
class SinglyLL:
def __init__(self):
self.head = Node()
self.tail = Node()
def prepend(self,value):
newnode = Node(value)
newnode.next = self.head
self.head = newnode
def append(self,data):
newnode = Node(data)
if self.head is None:
self.head = newnode
return
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = newnode
newnode.next = None
def display(self):
lis = []
cur = self.head
while cur.next != None:
cur = cur.next
lis.append(cur.value)
return lis
def fromarr(self,list):
for i in list:
temp = Node(i)
self.append(temp.value)
newsll = SinglyLL()
newsll.fromarr([1,2,3,4,5])
newsll.prepend(10)
print(newsll.display())
Expected output : [10,1,2,3,4,5]
Actual Output: [None,1,2,3,4,5]
Answers:
well you are initalising your head with a empty node, and displaying values from self.head.next
, so instead of setting element at position 0 you need to set element at position 1.
Adding below code for prepend
method
class Node:
def __init__(self,value=None):
self.value = value
self.next = None
class SinglyLL:
def __init__(self):
self.head = Node()
self.tail = Node()
def prepend(self,value):
newnode = Node(value)
if self.head is None:
self.head = newnode
else:
tmp = self.head.next
self.head.next = newnode
newnode.next = tmp
def append(self,data):
newnode = Node(data)
if self.head is None:
self.head = newnode
return
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = newnode
newnode.next = None
def display(self):
lis = []
cur = self.head
while cur.next != None:
cur = cur.next
lis.append(cur.value)
return lis
def fromarr(self,list):
for i in list:
temp = Node(i)
self.append(temp.value)
newsll = SinglyLL()
newsll.fromarr([1,2,3,4,5])
newsll.prepend(10)
print(newsll.display())
Your code has a mix of several approaches to organise a linked list data structure, but they are not compatible:
-
Your constructor creates a dummy node for the head
attribute, which could be an approach when you intend to append all data nodes after that dummy node. The display
method is in line with that approach as it doesn’t include the value of the dummy node in the result. But the prepend
nor the append
method use that approach as they treat the head
node as a data node.
-
Your constructor creates a dummy node for the tail
attribute. This is an approach that might be used for a doubly linked list, but is not useful for a singly linked list, as the process to append a new node at the end of the list cannot take benefit from this reference.
-
Although the constructor defines a tail
attribute none of the other methods make use of it, nor update it when necessary.
Some other remarks:
-
It is odd that the display
method does not display anything. It would be more appropriate to have an __iter__
method instead which would yield the linked list’s values.
-
fromarr
is not a very good name for a method that accepts a list.
-
It is not intuitive that this is an instance method, as its name suggests that it will create a new list from those values, but you actually need to first create a linked list instance yourself, and then call this method. I would suggest to drop this method and extend the constructor with optional arguments which will be used to populate the constructed linked list.
-
list
is a bad name for a parameter as this name is already in use by native Python.
-
It would be nice if the Node
constructor would accept an optional argument for defining the next
attribute.
Here is an update of your code that takes those points into account, and which uses the approach where:
- A
tail
attribute is set and used
- No dummy nodes are created
class Node:
def __init__(self, value=None, nxt=None):
self.value = value
self.next = nxt
class SinglyLL:
def __init__(self, *values):
# Don't create nodes here
self.head = self.tail = None
# Allow immediate population from arguments
for value in values:
self.append(value)
def prepend(self,value):
self.head = Node(value, self.head)
self.tail = self.tail or self.head
def append(self, data):
if not self.tail:
self.prepend(data)
else:
self.tail.next = self.tail = Node(data)
def __iter__(self):
cur = self.head
while cur:
yield cur.value
cur = cur.next
newsll = SinglyLL(1,2,3,4,5)
newsll.prepend(10)
print(list(newsll)) # [10, 1, 2, 3, 4, 5]
Code written in python:
prepend Function is supposed to add a value to the start of the Linked List
display Function is supposed to display the linked list in a List format in python
fromarr Function is supposed to add new nodes to the linked list
class Node:
def __init__(self,value=None):
self.value = value
self.next = None
class SinglyLL:
def __init__(self):
self.head = Node()
self.tail = Node()
def prepend(self,value):
newnode = Node(value)
newnode.next = self.head
self.head = newnode
def append(self,data):
newnode = Node(data)
if self.head is None:
self.head = newnode
return
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = newnode
newnode.next = None
def display(self):
lis = []
cur = self.head
while cur.next != None:
cur = cur.next
lis.append(cur.value)
return lis
def fromarr(self,list):
for i in list:
temp = Node(i)
self.append(temp.value)
newsll = SinglyLL()
newsll.fromarr([1,2,3,4,5])
newsll.prepend(10)
print(newsll.display())
Expected output : [10,1,2,3,4,5]
Actual Output: [None,1,2,3,4,5]
well you are initalising your head with a empty node, and displaying values from self.head.next
, so instead of setting element at position 0 you need to set element at position 1.
Adding below code for prepend
method
class Node:
def __init__(self,value=None):
self.value = value
self.next = None
class SinglyLL:
def __init__(self):
self.head = Node()
self.tail = Node()
def prepend(self,value):
newnode = Node(value)
if self.head is None:
self.head = newnode
else:
tmp = self.head.next
self.head.next = newnode
newnode.next = tmp
def append(self,data):
newnode = Node(data)
if self.head is None:
self.head = newnode
return
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = newnode
newnode.next = None
def display(self):
lis = []
cur = self.head
while cur.next != None:
cur = cur.next
lis.append(cur.value)
return lis
def fromarr(self,list):
for i in list:
temp = Node(i)
self.append(temp.value)
newsll = SinglyLL()
newsll.fromarr([1,2,3,4,5])
newsll.prepend(10)
print(newsll.display())
Your code has a mix of several approaches to organise a linked list data structure, but they are not compatible:
-
Your constructor creates a dummy node for the
head
attribute, which could be an approach when you intend to append all data nodes after that dummy node. Thedisplay
method is in line with that approach as it doesn’t include the value of the dummy node in the result. But theprepend
nor theappend
method use that approach as they treat thehead
node as a data node. -
Your constructor creates a dummy node for the
tail
attribute. This is an approach that might be used for a doubly linked list, but is not useful for a singly linked list, as the process to append a new node at the end of the list cannot take benefit from this reference. -
Although the constructor defines a
tail
attribute none of the other methods make use of it, nor update it when necessary.
Some other remarks:
-
It is odd that the
display
method does not display anything. It would be more appropriate to have an__iter__
method instead which would yield the linked list’s values. -
fromarr
is not a very good name for a method that accepts a list. -
It is not intuitive that this is an instance method, as its name suggests that it will create a new list from those values, but you actually need to first create a linked list instance yourself, and then call this method. I would suggest to drop this method and extend the constructor with optional arguments which will be used to populate the constructed linked list.
-
list
is a bad name for a parameter as this name is already in use by native Python. -
It would be nice if the
Node
constructor would accept an optional argument for defining thenext
attribute.
Here is an update of your code that takes those points into account, and which uses the approach where:
- A
tail
attribute is set and used - No dummy nodes are created
class Node:
def __init__(self, value=None, nxt=None):
self.value = value
self.next = nxt
class SinglyLL:
def __init__(self, *values):
# Don't create nodes here
self.head = self.tail = None
# Allow immediate population from arguments
for value in values:
self.append(value)
def prepend(self,value):
self.head = Node(value, self.head)
self.tail = self.tail or self.head
def append(self, data):
if not self.tail:
self.prepend(data)
else:
self.tail.next = self.tail = Node(data)
def __iter__(self):
cur = self.head
while cur:
yield cur.value
cur = cur.next
newsll = SinglyLL(1,2,3,4,5)
newsll.prepend(10)
print(list(newsll)) # [10, 1, 2, 3, 4, 5]