Python Linkledlist addNode() not correct - python

I'm writing a simple linked list implementation and am struggling to understand why my code doesn't work. I have a ListNode class and a LinkedList node which contains the head and tail nodes of the list. The addNode() function simply creates a new ListNode, change the self.tail.next = newNode, then set the tail to be the newNode.
When I try to run the following code, I would get the error "AttributeError: 'int' object has no attribute 'next'".
l1 = LinkedList(1)
l1.addNode(2)
l1.addNode(4)
Thank you for the help!
Here is my code
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self, head=ListNode()):
self.head = head
self.tail = head
def addNode(self, val=0):
newNode = ListNode(val)
self.tail.next = newNode
self.tail = newNode

On the first line of your code, you're passing the value 1 to LinkedList, which is an integer, not an instance of ListNode.
So, you should write l1 = LinkedList(ListNode(1)).

Related

Problem understanding Linked Lists in Python

I'm learning about data structures and algorithms and I'm starting to learn about constructing linked lists from scratch in python. Right now I understand how they work and the components that go into making them (Nodes, data/address, Head/Tail, etc), but I'm having a really hard time wrapping my brain around how they function when constructing them in python. Like I have working code to make them in python here but I don't get the logic behind how they operate with classes. For example, I'm confused in my addLast-function on how the node variable(node = Node(value)) connects to the Node class.
class Node:
def __init__(self, value, next=None):
self.value = value
self.next = next
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def addLast(self, value):
node = Node(value)
if self.head == None:
self.head = node
self.tail = node
else:
self.tail.next = node
self.tail = node
class Node:
def __init__(self, value, next=None):
self.value = value
# NODE POINTS TO THE NEXT ELEMENT IF PROVIDED ELSE NONE
self.next = next
class LinkedList:
def __init__(self):
# INIT AN EMPTY LINKED LIST
self.head = None
self.tail = None
def addLast(self, value):
# CREATE A NODE OBJECT WITH VALUE 'value' WHICH POINTS TO NOTHING (because it's the end of the linked list)
node = Node(value)
# IF NO HEAD IT BECOMES THE HEAD AND THE TAIL
if self.head == None:
self.head = node
self.tail = node
else:
# ADD THE NODE TO THE END (tail) OF THE LINKED LIST
self.tail.next = node
self.tail = node
# Create an empty linked_list
head = Linked_list()
# Add at the end a node with the value 1
head.addLast(1)
Hope it's clearer for you, ask questions if needed
I think this may help you understand what the code actually do hedind the scenes.
You can paste the following code to the link and click the "Visualize Execution" button. It will visualize all details step by step.
Good Luck!
class Node:
def __init__(self, value, next=None):
self.value = value
self.next = next
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def addLast(self, value):
node = Node(value)
if self.head == None:
self.head = node
self.tail = node
else:
self.tail.next = node
self.tail = node
head = LinkedList()
head.addLast(1)
head.addLast(2)

LinkedList implementation in Python not showing beyond the head node

My attempts at creating a linked list from scratch in Python are not working, and I'm not sure what I am missing. I tried to create separate classes for nodes and linked lists, but when I am trying to see beyond the head node, I hit a road block.
Appreciate any pointers (no pun intended). Also, what is a better approach: have a separate class for the nodes, or make them an attribute of the linked list class itself?
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self):
self.head = None
# adding/inserting to the tail
def add(self, val):
node_to_add = ListNode()
if self.head == None:
self.head = node_to_add
node_to_add.val = val
else:
self.next = node_to_add
node_to_add.val = val
# printing the linked list as a list
def print(self):
list_to_print = []
if not self.head:
return None
node_to_read = self.head
while self.head:
list_to_print.append(node_to_read.val)
if node_to_read.next:
self.head = node_to_read.next
else:
return list_to_print
When I run this code, I only can print the head node. When I add nodes/values after the first entry, the print() only returns the head.
test1 = LinkedList()
test1.add(1)
test1.add(4)
test1.add(7)
test1.print()
the output is
[1]
In order to append items to the last Node you need to keep track of the last node.
You also should not override your head pointer in the print function.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
# adding/inserting to the tail
def add(self, val):
node_to_add = ListNode()
node_to_add.val = val
if self.tail == None:
self.head = node_to_add
self.tail = node_to_add
else:
self.tail.next = node_to_add
self.tail = node_to_add
# printing the linked list as a list
def print(self):
list_to_print = []
if not self.head:
return None
current_node = self.head
while current_node:
list_to_print.append(current_node.val)
if current_node.next:
current_node = current_node.next
else:
return list_to_print
You can simplify this significantly by giving the node responsibility for adding children. This makes the linked list object basically a wrapper that manages the head and iterations over the list:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def add(self, node):
if self.next is None:
self.next = node
else:
self.next.add(node)
class LinkedList:
def __init__(self):
self.head = None
def add(self, val):
node = ListNode(val)
if self.head == None:
self.head = node
else:
self.head.add(node)
# printing the linked list as a list
def print(self):
list_to_print = []
node_to_read = self.head
while node_to_read:
list_to_print.append(node_to_read.val)
node_to_read = node_to_read.next
print(list_to_print)
test1 = LinkedList()
test1.add(1)
test1.add(4)
test1.add(7)
test1.print()
# [1, 4, 7]

'int' object has no attribute 'next'

So i've been trying to solve a problem in leetcode that is to design a linked list. Here's what i tried:
class Node:
def __init__(self,next=None,val=None):
self.next = next
self.val = val
class Linked_list(object):
def __init__(self):
self.head = None
self.length = 0
def insertAtEnd(self, val):
new_node = Node(val)
if self.head is None:
self.head = new_node
else:
itr = self.head
while itr.next: #Error
itr = itr.next
itr.next = new_node
self.length += 1
So in the insertAtEnd method when i try to iterate over the list it shows the error that self.head is an an int object. I'm struggling to find an answer here. So please help me out. Thank you!
Your code is fine but I found one bug there
new_node = Node(val)
But constructor looks:
def __init__(self,next=None,val=None):
self.next = next
self.val = val
So you pass your val to next parameter and self.head.next points to val which is int. Probably you ment
new_node = Node(val=val)
Or alternatively, change order of next and val in Node constructor.

how is the object using a variable which is not inside the class or defined anywhere

In this code the object of class Node is using a variable next which is not defined anywhere and the code is still working HOW?How is the object using a variable which is not defined in its class
class Node:
def __init__(self, data):
self.data = data
class LinkedList:
# Function to initialize head
def __init__(self):
self.head = None
# Function to reverse the linked list
def reverse(self):
prev = None
current = self.head
while(current is not None):
next = current.next
current.next = prev
prev = current
current = next
self.head = prev
# Function to insert a new node at the beginning
def push(self, new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
# Utility function to print the linked LinkedList
def printList(self):
temp = self.head
while(temp):
print(temp.data)
temp = temp.next
llist = LinkedList()
llist.push(20)
llist.push(4)
llist.push(15)
llist.push(85)
print( "Given Linked List")
llist.printList()
llist.reverse()
print ("\nReversed Linked List")
llist.printList()
While in most strongly typed languages this is not possible, Python allows instance attributes to be defined even after the instance has been created and the constructor has run. As long as code does not reference an attribute before it has been defined, there is no issue. See also: Can I declare Python class fields outside the constructor method?
In this particular case the following code would produce an error:
node = Node(42)
if node.next: # Attribute error
print("42 is not the last node")
else:
print("42 is the last node")
However, the only place where new node instances are created is in the push method of the LinkedList class:
def push(self, new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
As you can see, the next attribute is defined immediately after the node is constructed. So in practice, every node in a linked list will have a next attribute.
Best Practice?
It is open for debate whether this coding practice is advisable. For instance, Pylint has a rule defining-attr-methods which by default will raise a warning when attributes are defined outside of __init__, __new__, setUp, or __post_init__.
Alternative
In this scenario I would certainly prefer to define the next attribute in the constructor, and give the constructor an extra, optional parameter with which next can be initialised:
class Node:
def __init__(self, data, nxt=None):
self.data = data
self.next = nxt
With this change, the push method of the LinkedList class can be reduce to just:
class LinkedList:
# ...
def push(self, new_data):
self.head = Node(new_data, self.head)
That looks a lot more elegant.
Unrelated, but I would also let the constructor of LinkedList accept any number of values to initialise the list with:
class LinkedList:
def __init__(self, *values):
self.head = None
for value in reversed(values):
self.push(value)
Now the main code could create a list with 4 values in one go:
llist = LinkedList(85, 15, 4, 20)

reversing a linkedlist using 3 pointers

reversing a linkedlist using 3 pointer?
cant understand what is the problem?
pls suggest any other iterative solution too..
reversing a linkedlist using 3 pointer?
cant understand what is the problem?
pls suggest any other iterative solution too..
outcome should be 87654321(reverse of a linkedlist)
but currently the output is 1
i think there is problem in reverse function pointers
reversing a linkedlist
class Node:
def __init__(self,data):
self.data=data
self.next=None
class LinkedList:
def __init__(self):
self.head=None
def push(self,data):
new_node=Node(data)
new_node.next=self.head
self.head=new_node
def printlist(self):
temp=self.head
print()
while temp:
print(temp.data,end=' ')
temp=temp.next
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):
last = last.next
last.next = new_node
def reverse(self):
prev=None
current=self.head
nnext=current.next
while nnext:
current.next=prev
prev = current
current = nnext
nnext=nnext.next
current.next=prev
if __name__=='__main__':
llist=LinkedList()
llist.append(1)
llist.append(2)
llist.append(3)
llist.append(4)
llist.append(5)
llist.append(6)
llist.append(7)
llist.append(8)
llist.printlist()
llist.reverse()
llist.printlist()
Well, your code generally works fine. What you miss is assigning self.head in the end of your reverse method. Just add this line self.head = current to the end of reverse and it works fine.

Categories