Create a linked list without initializing an empty node - python

I create a linked list using python class. But I can't manipulate the output format:
class Node:
def __init__(self, item=None):
self.item = item
self.next = None
class LinkedList:
def __init__(self):
self.head = Node()
def showElements(self):
curr = self.head
while curr is not None:
print(curr.item)
curr = curr.next
def append(self, item):
new_node = Node(item)
curr = self.head
while curr.next != None:
curr = curr.next
curr.next = new_node
llist = LinkedList()
llist.append(1)
print(llist.head.item) # output: None // But I want here to display 1
llist.append(2)
print(llist.head.next.item) # output: 1 // But I want here to display 2
llist.showElements() # output: None 1 2 // I want only 1 2
Maybe my first head node create this problem. But without initializing an empty node how could I create the reference of the next node using the next attribute?

You have to assign the head in the append function if there's no head already. The head was always an Empty Node
class Node:
def __init__(self, item=None):
self.item = item
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def showElements(self):
curr = self.head
while curr is not None:
print(curr.item)
curr = curr.next
def append(self, item):
if self.head is None:
self.head = Node(item)
return
new_node = Node(item)
curr = self.head
while curr.next is not None:
curr = curr.next
curr.next = new_node

Your append method sets head.next to new_node, but it never sets head.item, which is why you get output=None.
So with this implementation, the head doesn't store an actual element, it's just used as a starting point for the list. That's not necessarily a problem, it's one implementation choice.
You could also change the implementation to store an item in head, why not.
Whatever the choice, I would suggest implementing first() and next() methods to hide the implementation details.

Related

Python : I am not able to prepend a Value in a Singly Linked list

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. 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]

Python linked-list issues of receiving memory addresses when printing unless double calling

I am creating a Linked List implementation and I cannot fix this error of having to double call node.val.val to print the data instead of the memory address.
Here is my implementation:
class LinkedNode:
def __init__(self, val, nxt=None):
self.val = val
self.nxt = nxt
class LinkedList:
def __init__(self, head=None):
self.head = head
def append(self, new_val):
node = LinkedNode(new_val, None)
if self.head:
curr = self.head
while curr.nxt:
curr = curr.nxt
curr.nxt = node
else:
self.head = node
def print(self):
curr = self.head
while curr:
**print(curr.val)**
curr = curr.nxt
l1 = LinkedList()
l1.append(LinkedNode(2))
l1.append(LinkedNode(3))
l1.append(LinkedNode(4))
l1.print()
When the line in the print function is "print(curr.val)", the function prints memory addresses. When the line is "print(curr.val.val)", the function prints 2,3,4.
Does anyone have a possible solution?
You were passing a LinkedNode() object as an argument to .append() function:
class LinkedNode:
def __init__(self, value, nxt=None):
self.val = value
self.nxt = nxt
class LinkedList:
def __init__(self, head=None):
self.head = head
def append(self, new_val):
node = LinkedNode(new_val, None) #Creation of LinkedNode from integer
if self.head:
curr = self.head
while curr.nxt:
curr = curr.nxt
curr.nxt = node
else:
self.head = node
def print(self):
curr = self.head
while curr:
print(curr.val)
curr = curr.nxt
l1 = LinkedList()
l1.append(2) #Argument must be integer, not LinkedNode(integer)
l1.append(3) #Because you are already converting integer to LinkedNode on append function
l1.append(4)
l1.print()
Output:
2
3
4
Because in these lines you are creating LinkedNode objects not values!
l1.append(LinkedNode(2))
l1.append(LinkedNode(3))
l1.append(LinkedNode(4))
After that, you created a new LinkedNode(LinkedNode(2), None) within the scope of the append function.
Change it to:
l1.append(2)
l1.append(3)
l1.append(4)

How to retrieve the first added node when a LinkedList is created?

I have created a linkedlist in Python using below classes:
class: Node
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
class LinkedList:
def __init__(self):
self.head = None
def insert_at_beginning(self, data):
temp = Node(data)
if self.head is None:
self.head = temp
else:
temp.next = self.head
self.head = temp
def insert_at_end(self, data):
temp = Node(data)
if self.head is None:
self.head = temp
else:
curr = self.head
while curr.next is not None:
curr = curr.next
curr.next = temp
def insert_at_position(self, pos, data):
temp = Node(data)
if self.head is None:
self.head = temp
else:
curr = self.head
i = 1
while i < pos:
curr = curr.next
i += 1
temp.next = curr.next
curr.next = temp
def traverse_list(self):
if self.head is None:
print('List is empty')
else:
curr = self.head
while curr.next is not None:
print(curr.data)
curr = curr.next
Below is the order I am calling the insertion methods.
ll = LinkedList()
ll.head = Node(1)
ll.insert_at_beginning(data=10)
ll.insert_at_beginning(data=11)
ll.traverse()
The elements printed in the output are: 11 & 10 which are the ones I inserted but I don't see the value 1 which is a node I added in the beginning.
Is there any logic I missed here that is making the first value skip or not being considered ?
Your problem comes from while curr.next is not None: in traverse_list(). Assuming you're pointing your last node, its next node is obviously None. Therefore, it will stop the loop before printing the last node's data.
You can try this:
def traverse_list(self):
if self.head is None:
print('List is empty')
else:
curr = self.head
while curr is not None:
print(curr.data)
curr = curr.next

why the element not appending in linked list?

not getting expected output. Missing node with data = 6
looks like not insertAfter method properly,
cant find the issue.
pls suggest any other issue too as i am just started with data structures. is there anything need to be kept in mind while studying data structures.
class Node:
def __init__(self,data):
self.data = data
self.next = None
class LinkeList:
def __init__(self):
self.head = None
def push(self,new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
def insertAfter(self,prev_node,new_data):
new_node = Node(new_data)
if self.head is None:
self.head = new_node
return
new_node.next = prev_node.next
prev_node.next = new_node
def append(self,new_data):
new_node = Node(new_data)
if self.head is None:
self.head = new_node
return
last = self.head
while last.next != None:
last = last.next
last.next = new_node
def printList(self):
temp = self.head
while temp is not None:
print(temp.data, end = " ")
temp = temp.next
if __name__ =='__main__':
llist = LinkedList()
llist.append(7)
llist.append(8)
llist.push(5)
llist.insertAfter(Node(5),6)
llist.printList()
So the issue is in this line,
llist.insertAfter(Node(5),6)
When you do insertAfter then you need to first get a Node from the current linked list, rather what you are doing is, that you create a new node, then pass it. That new node might have the same value as a . node in your linked list, but it really isn't a part of it, what you need to do is as follows
First implement a get node function, that gets a node from the linked list with the value that you want, something like this
def getNode(self, value):
temp = self.head
while temp is not None:
if temp.value == value:
return temp
else:
temp = temp.next
return None
then do this.
llist.insertAfter(llist.getNode(5),6)
Also put a check for if passed node is not None in insertAfter

constructing a Queue linked list using only one head pointer

I'm trying to construct a Queue linked list using only a head pointer (no tail).
but i cant seem to enqueue at the end of the list.
example: at the moment the code will: c -> b -> a, however i would like reverse it a -> b -> c.
class Node:
'''A node for a linked list.'''
def __init__(self, initdata):
self.data = initdata
self.next = None
class Queue(object):
def __init__(self):
self.head = None
def enqueue(self, item):
"""Add an item onto the tail of the queue."""
if self.head == None:
temp = Node(item)
temp.next = self.head
self.head = temp
else:
current = self.head
while current != None:
current = current.next
if current == None:
temp = Node(item)
temp.next = current
current = temp
def dequeue(self):
if self.head == None:
raise IndexError("Can't dequeue from empty queue.")
else:
current_first = self.head
current = self.head.next
return current_first.data
This should do it:
class Node:
'''A node for a linked list.'''
def __init__(self, initdata):
self.data = initdata
self.next = None
class Queue(object):
def __init__(self):
self.head = None
def enqueue(self, item):
"""Add an item onto the tail of the queue."""
if self.head is None:
self.head = Node(item)
else:
current = self.head
while current.next is not None:
current = current.next
current.next = Node(item)
def dequeue(self):
if self.head is None:
raise IndexError("Can't dequeue from empty queue.")
else:
first = self.head
self.head = self.head.next
return first.data
Besides some logic fixes (we need to create a new node and store it in current.next, current is just a variable pointing to a node), note we use is operator for testing for None and Node constructor to set data (so we can create and assign new nodes without temp var).
For example:
q = Queue()
q.enqueue('a')
q.enqueue('b')
q.enqueue('c')
print(q.dequeue())
print(q.dequeue())
print(q.dequeue())
Outputs:
a
b
c
Btw, note that such structure requires O(N) insertion time and O(1) deletion (pop) time. Double-ended queue (like the standard collections.deque) will do both insertion and deletion in constant time.

Categories