How to select the first node in linked list? - python

I want to select the first node in the linked list and present the selected node. This is the whole code that I've created. The "prepend" adds the node before the first node. The "append" adds the node after the last of the linked list.
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
# LinkedList definition here
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def prepend(self, data):
node = Node(data, self.head)
if self.head is None:
self.head = node
self.tail = node
else:
node.next = self.head
self.head = node
def append(self, data):
node = Node(data, None)
if self.tail is None:
# No elements in list
self.head = node
self.tail = node
else:
self.tail.next = node
self.tail = node
def pop_start(self):
if self.head is None:
return None
if self.head.next is None:
cur = self.head
self.head = None
return cur
else:
if self.head != None:
temp = self.head
self.head = self.head.next
return temp
names = LinkedList()
names.append("Bill Gates")
names.append("Steve Jobs")
names.prepend("Jody")
print(names.pop_start())
I can get the result of Jody. But if instead, I test for
print(names.pop_start() == "Jody")
It shows False. What is the reason?

names.pop_start() returns a Node object. Its data is the string 'Jodie', and because of how you've defined its __str__ method, when you print the node, the string is what you'll see. But the node itself is a node, not a string.
If you compare to the data attribute:
print(names.pop_start().data == "Jody")
...you'll get True, as intended. But it would probably make more sense for pop_start to just return the data anyway, rather than the Node object. Here's how you could do that:
def pop_start(self):
if self.head is None:
return None
else:
data = self.head.data
if self.head is self.tail:
self.tail = None
self.head = self.head.next
return data

Related

How do I fix the adding value in middle of linked list location?

I'm creating a single linked list insert beginning, end, and middle of the linked list. After running code inserting the middle is not working in the linked list changing location value randomly and after running it's not getting.
Can anyone suggest what is wrong with the code:
class Node:
def __init__(self, value=None):
self.value = value
self.next = None
class SLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __iter__(self):
node = self.head
while node:
yield node
node = node.next
def insertsll(self, value, location):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
else:
if location == 0:
new_node.next = self.head
self.head = new_node
elif location == 1:
new_node.next = None
self.tail.next = new_node
self.tail = new_node
else:
temp_node = self.head
index = 0
while index < location - 1:
temp_node = temp_node.next
index += 1
next_node = temp_node.next
temp_node.next = new_node
new_node.next = next_node
# if temp_node == self.tail:
# self.tail = new_node
sll = SLinkedList()
sll.insertsll(1, 1)
sll.insertsll(2, 1)
sll.insertsll(3, 1)
sll.insertsll(4, 1)
sll.insertsll(0, 0)
sll.insertsll(60, 3)---> run this random changing location not working in correct location
sll.insertsll(50, 4)---> run this random changing location not working in correct location
print([node.value for node in sll])
Output:
[0, 1, 50, 2, 3, 4]
Process finished with exit code 0
I think the iteration in the while loop was a little bit too complicated. I think with this code it is more understandable what the insert does. Also, I don't know why you had the location === 1 check. It seems to be not necessary.
class Node:
def __init__(self, value=None):
self.value = value
self.next = None
class SLinkedList:
def __init__(self):
self.head = None
self.tail = None
def __iter__(self):
node = self.head
while node:
yield node
node = node.next
def insertsll(self, value, location):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
else:
if location == 0:
new_node.next = self.head
self.head = new_node
else:
temp_node = self.head
index = 0
# Iterate to insert location
while index < location - 1:
index += 1
temp_node = temp_node.next
# Insert new node
new_node.next = temp_node.next
temp_node.next = new_node
# Check if new node is tail
if new_node.next is None:
self.tail = new_node
sll = SLinkedList()
sll.insertsll(1, 1)
sll.insertsll(2, 1)
sll.insertsll(3, 1)
sll.insertsll(4, 1)
sll.insertsll(0, 0)
sll.insertsll(60, 3)
sll.insertsll(50, 4)
print([node.value for node in sll])
Output:
[0, 1, 4, 60, 50, 3, 2]
P.S.: Such a structure really benefits from a length attribute. This can be used to check if an insert operation is even allowed. Probably, you should consider adding it.

calling a method in another method errors

class Node:
def __init__(self, data):
self.data = data
self.ref = None
class LinkedList:
def __init__(self):
self.head = None
def show(self):
if self.head is None:
print("This linked lists is empty")
else:
currentnode = self.head
while currentnode is not None:
print(currentnode.data, end=" --> ")
currentnode = currentnode.ref
def addelement(self, value):
newnode = Node(value)
newnode.ref = self.head
self.head = newnode
def lenofll(self , i = 0):
while self.head is not None:
i = i +1
self.head = self.head.ref
return i
def middle(self):
i = 0
lent = self.lenofll()
if self.head is None: # self.head changed to None after calling lenofll method.
print("linked list is empty")
I wanted to get the length of linked lists in the middle method. But as I called self.lenofll(), it changed the self.head to None.
What can I do to fix this?
Indeed, doing self.head = self.head.ref modifies the head. You should not make any modifications to self.head in a method whose job is just to search in the list -- without modifying anything to it.
As you can see, that method keeps looping until self.head is not None is not true, i.e. when self.head is None. No wonder that self.head is None after running this method!
Use a local variable for this iteration instead:
def lenofll(self, i = 0):
node = self.head # use local variable
while node is not None:
i += 1
node = node.ref
return i

Implementing a LinkedList in Python - Is leetcode wrong?

I'm working on this problem: https://leetcode.com/explore/learn/card/linked-list/209/singly-linked-list/1290/
and leetcode is telling me that my code is throwing a runtime error. The input it's trying to make my code run is this:
["MyLinkedList","addAtHead","deleteAtIndex","addAtHead","addAtHead","addAtHead","addAtHead","addAtHead","addAtTail","get","deleteAtIndex","deleteAtIndex"]
[[],[2],[1],[2],[7],[3],[2],[5],[5],[5],[6],[4]]
Where the first array contains the function name and the second contains the function parameters. E.g. the second element adds a 2 at the head of the linkedlist. My question is that how would it be OK to be deleting the element at index 1 when there is only one element in the linkedlist? Is there some special thing about linked lists that I should know or is the input case incorrect. Below is my code for reference.
class SinglyLinkedList():
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def get(self, index):
if index<0 or index>self.length: raise AssertionError("get index must be in bounds")
node = self.head
for _ in range(index):
node = node.next
return node
def addAtHead(self, val):
node = SinglyListNode(val)
if self.length==0:
self.head = node
self.tail = self.head
else:
node.next = self.head
self.head = node
self.length+=1
def addAtTail(self, val):
node = SinglyListNode(val)
if self.length==0:
self.tail = node
self.head = self.tail
else:
self.tail.next = node
self.tail = node
self.length+=1
def addAtIndex(self, index, val):
if index<0 or index>self.length:
raise AssertionError(f"index at which to add ({index}) is out of bounds")
if index==0:
return self.addAtHead(val)
if index==self.length:
return self.addAtTail(val)
newNode = SinglyListNode(val)
node = self.head
for _ in range(index-1):
node = node.next
newNode.next = node.next
node.next = newNode
self.length+=1
def deleteAtIndex(self, index):
if index<0 or index>self.length:
raise AssertionError(f"index at which to add ({index}) is out of bounds")
if index==0:
self.head = self.head.next
elif index==self.length-1:
self.tail=self.get(self.length-2)
else:
node = self.head
for _ in range(index-1):
node = node.next
node.next = node.next.next
self.length-=1
def __str__(self):
res = "["
node = self.head
for _ in range(self.length-1):
res += str(node)+","
node = node.next
res += str(node)+f"] ({self.length})"
return res
From https://leetcode.com/problems/design-linked-list/
void deleteAtIndex(int index) Delete the indexth node in the linked list, if the index is valid.
Looks like the delete needs to be done only when the index is valid. Your code needs to handle the case when the index is invalid.

Why do I get AttributeError: 'NoneType' object has no attribute 'value'?

Below is my code in python. I'm basically trying to look through a linked list to see if a specific element is in that list. The code works if the item is in the list, but not if it doesn't. I believe the problem lies within the loop coming to the end of the list and the last node, but I'm not sure how to fix the error. Any help would be appreciated. (Edited to include the classes used)
class Node:
def __init__(self, data):
#raise error for wrong data input type
if not type(data) in [int, float, str]:
raise TypeError("data must be an integer, float, or string")
self.value = data
class LinkedListNode(Node):
def __init__(self, data):
Node.__init__(self, data) # Use inheritance to set self.value.
self.next = None # Reference to the next node.
self.prev = None # Reference to the previous node.
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def append(self, data):
# Create a new node to store the input data.
new_node = LinkedListNode(data)
if self.head is None:
# If the list is empty, assign the head and tail attributes to
# new_node, since it becomes the first and last node in the list.
self.head = new_node
self.tail = new_node
self.length += 1
else:
# If the list is not empty, place new_node after the tail.
self.tail.next = new_node # tail --> new_node
new_node.prev = self.tail # tail <-- new_node
# Now the last node in the list is new_node, so reassign the tail.
self.tail = new_node
self.length += 1
def find(self, data):
x = range(self.length)
current_position = self.head.value
current_node = self.head
for i in x:
if current_position == data:
return self.head
else:
current_node = current_node.next
current_position = current_node.value
if current_position != data:
raise ValueError("data point is not in the list")
return

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

Categories