I am trying to understand why does inserting the same node twice in a singly linked list causes an infinite loop.
I tried to insert the last node as the new head node. But when I run the code, it's starting an infinite loop I can see since I am calling a method to print nodes at the end. Here's my code.
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def insertLast(self, newNode):
if self.head is None:
self.head = newNode
else:
lastNode = self.head
while True:
if lastNode.next is None:
break
lastNode = lastNode.next
lastNode.next = newNode
def insertHead(self, newNode):
# x, y ,z. => new head, x,y,z
if self.head is None:
print("List is empy please call inserlast()")
else:
currentHead = self.head
self.head = newNode
self.head.next = currentHead
def printList(self):
if self.head is None:
print("EMPTY List. No Data found!")
return
else:
currentNode = self.head
while True:
print(currentNode.data)
currentNode = currentNode.next
if currentNode is None:
break
node1 = Node("Head")
node2 = Node("Some Data")
node3 = Node("Some More Data")
# I am adding this node at the end of the list
newnode1 = Node("New Head")
linkedList = LinkedList()
# create a new linked list by inserting at end
linkedList.insertLast(node1)
linkedList.insertLast(node2)
linkedList.insertLast(newnode1)
# using a node i have already added in the list as New head of the list
linkedList.insertHead(newnode1)
linkedList.printList()
When you re-add an existing node to the list, you don't do anything about existing nodes that already referenced the re-added node. In your case, you now have a node at the end of the list whose next points back to the node which has just become the head, and so now your list is circular, which is going to cause any function which tries to traverse the list to infaloop.
There are three ways I can think of to solve this, and I'll save the best for last:
Add cycle detection logic to protect you from infalooping when your list becomes circular (i.e. break the cycles or just stop traversing once you get back to someplace you've already been). This is nontrivial and IMO not a great solution; better to keep the list from getting broken in the first place than have to constantly check to see if it needs fixing.
Add a removeNode function to ensure that a given node has been fully removed from the list (i.e. by scanning through the whole list to see what other nodes, if any, reference the given node, and adjusting pointers to skip over it). Then you can safely re-insert a node by first removing it. Note: if the caller passes you a Node that belongs to a DIFFERENT list, you can still end up in trouble, because you'll have no way of finding that other list! Circular structures will still be possible by building lists and then inserting the nodes of each into the other.
Don't allow callers of your list class to access the actual nodes at all; have them insert values (rather than nodes) so that you can ensure that they're never giving you a node with weird pointer values (a node that belongs to another list, a node that points to itself, etc). The pointers should be completely internal to your linked list class rather than something that the caller can mess up.
Briefly, according to your code, the infinite loop you face results from the fact that The linked list does not arrange the nodes physically, it just tells each node which node is next.
Let us explain it in details:
As shown, each node has a next attribute which is set by LinkedList to the next one.
after initiating the Nodes
node1.next mentions to None
node2.next mentions to None
newnode1.next mentions to None
after creating the linked list
node1.next mention to Node2
node2.next mention to Newnode1
newnode1.next mention to None
after inserting Newnode1 again as a head, the linked list set Nownode1.next to mention to Node1, and the hole figure becomes:
node1.next mention to Node2
node2.next mention to Newnode1
newnode1.next mention to Node1
Therefor, it becomes a closed loop
The linked list does not arrange the nodes physically, it just tells each node which node is next.
That is the explanation of the infinite loop you face.
Good Luck
Related
I solved an exercise where I had to apply a recursive algorithm to a tree that's so defined:
class GenericTree:
""" A tree in which each node can have any number of children.
Each node is linked to its parent and to its immediate sibling on the right
"""
def __init__(self, data):
self._data = data
self._child = None
self._sibling = None
self._parent = None
I had to concatenate the data of the leaves with the data of the parents and so on until we arrive to the root that will have the sum of all the leaves data. I solved it in this way and it works but it seems very tortuous and mechanic:
def marvelous(self):
""" MODIFIES each node data replacing it with the concatenation
of its leaves data
- MUST USE a recursive solution
- assume node data is always a string
"""
if not self._child: #If there isn't any child
self._data=self._data #the value remains the same
if self._child: #If there are children
if self._child._child: #if there are niece
self._child.marvelous() #reapply the function to them
else: #if not nieces
self._data=self._child._data #initializing the name of our root node with the name of its 1st son
#if there are other sons, we'll add them to the root name
if self._child._sibling: #check
current=self._child._sibling #iterating through the sons-siblings line
while current:
current.marvelous() #we reapplying the function to them to replacing them with their concatenation (bottom-up process)
self._data+=current._data #we sum the sibling content to the node data
current=current._sibling #next for the iteration
#To add the new names to the new root node name:
self._data="" #initializing the root str value
current=self._child #having the child that through recursion have the correct str values, i can sum all them to the root node
while current:
self._data+=current._data
current=current._sibling
if self._sibling: #if there are siblings, they need to go through the function themselves
self._sibling.marvelous()
Basically I check if the node tree passed has children: if not, it remains with the same data.
If there are children, I check if there are nieces: in this case I restart the algorithm until I can some the leaves to the pre-terminal nodes, and I sum the leaves values to put that sum to their parents'data.
Then, I act on the root node with the code after the first while loop, so to put its name as the sum of all the leaves.
The final piece of code serves as to make the code ok for the siblings in each step.
How can I improve it?
It seems to me that your method performs a lot of redundant recursive calls.
For example this loop in your code:
while current:
current.marvelous()
self._data += current._data
current = current._sibling
is useless because the recursive call will be anyway performed by the last
instruction in your method (self._sibling.marvelous()). Besides,
you update self._data and then right after the loop you reset
self._data to "".
I tried to simplify it and came up with this solution that seems to
work.
def marvelous(self):
if self.child:
self.child.marvelous()
# at that point we know that the data for all the tree
# rooted in self have been computed. we collect these
self.data = ""
current = self.child
while current:
self.data += current.data
current = current.sibling
if self.sibling:
self.sibling.marvelous()
And here is a simpler solution:
def marvelous2(self):
if not self.child:
result = self.data
else:
result = self.child.marvelous2()
self.data = result
if self.sibling:
result += self.sibling.marvelous2()
return result
marvelous2 returns the data computed for a node and all its siblings. This avoids performing the while loop of the previous solution.
Python 3 Problem
I need to know how to solve the problem, here is my code (obviously incorrect) and I also attached the link of the hackerrank challenge. All of the previous answers is in older python and the exercise itself has considerably changed. All you have to do is insert data at the tail of the linked list.
Thank you very much and have a good day.
def insertNodeAtTail(head, data):
if head == None:
head.data = data
return head
else:
while head:
head = head.next
head.data = data
return head
Found the answer
def insertNodeAtTail(head, data):
if head is None:
return SinglyLinkedListNode(data)
pnt = head
while pnt.next:
pnt = pnt.next
pnt.next = SinglyLinkedListNode(data)
return head
Well, right off the bat, I can see a big problem. You check for head == None, and if that is True, then you proceed to try to set the data attribute in an object that doesn't exist...in None. Also, you should be using if head is None. If that succeeds, what you probably want to do is create a new Node object, set its data attribute to the incoming data, and set head to point to that new node.
You have a similar issue with the other half of your code. Your code doesn't add a Node in the case of an existing list either...it just changes the data that the last Node in the list is pointing to. Here, you want to create a Node containing your passed in data, and point node.next to it.
I don't know the details of how you create a node, but here's about what your code should look like:
def insertNodeAtTail(head, data):
if head is None:
head = Node(data)
return head
else:
node = head
while node.next:
node = node.next
node.next = Node(data)
return head
It is assumed that Node() sets its next attribute to None and sets its data attribute to the passed in data.
I had a quiz recently and this is what the question looked like:-
You may use the following Node class:
class Node:
"""Lightweight, nonpublic class for storing a singly linked node."""
__slots__ = 'element', 'next' # streamline memory usage
def __init__(self, element, next): # initialize node's fields
self.element = element # reference to user's element
self.next = next # reference to next node
Assume you have a singly-linked list of unique integers. Write a Python method that traverses this list to find the smallest element, removes the node that contains that value, and inserts the smallest value in a new node at the front of the list. Finally, return the head pointer. For simplicity, you may assume that the node containing the smallest value is not already at the head of the list (ie, you will never have to remove the head node and re-add it again).
Your method will be passed the head of the list as a parameter (of type Node), as in the following method signature:
def moveSmallest(head):
You may use only the Node class; no other methods (like size(), etc) are available. Furthermore, the only pointer you have is head (passed in as a parameter); you do not have access to a tail pointer.
For example, if the list contains:
5 → 2 → 1 → 3
the resulting list will contain:
1 → 5 → 2 → 3
Hint 1: There are several parts to this question; break the problem down and think about how to do each part separately.
Hint 2: If you need to exit from a loop early, you can use the break command.
Hint 3: For an empty list or a list with only one element, there is nothing to do!
My answer:
def moveSmallest(h):
if h==None or h.next==None:
return h
# find part
temp=h
myList=[]
while temp!=None:
myList.append(temp.element)
temp=temp.next
myList.sort()
sv=myList[0]
# remove part
if h.element==sv and h.next!=None:
h=h.next
else:
start=h
while start!=None:
if start.next.element==sv and start.next.next!=None:
start.next=start.next.next
break
if start.next.element==sv and start.next.next==None:
start.next=None
break
start=start.next
# Insert part
newNode=Node(sv)
newNode.next=h
h=newNode
return h
Mark received=10/30
Feedback on my answer:
"Not supposed to use sorting; searching the list should be the way we've covered in class.
You're advancing too far ahead in the list without checking whether nodes exist.
Review the 'singly-linked list' slides and answer this question as the examples suggest."
As you can see I am finding the element in the list and removing it and then adding it to the list as a head node. I ran this code and it works fine. As you can see in the feedback he says "You're advancing too far ahead in the list without checking whether nodes exist." which is taken care by the first if statement in my answer and for "Not supposed to use sorting; searching the list should be the way we've covered in class." I believe my mistake was to use the list at the first place but given the code the final score should be or be more than 20/30. Can you guys please check this or give your opinion on this feedback?
As you can see in the feedback he says "You're advancing too far ahead
in the list without checking whether nodes exist." which is taken care
by the first if statement in my answer
It's not taken care of. The first if-statement of your function just checks to see if the head exists and that the node following the head exists as well (basically, asserting that you have at least two nodes in the linked list).
What you have:
if h.element==sv and h.next!=None:
h=h.next
else:
start=h
while start!=None:
if start.next.element==sv and start.next.next!=None:
If you enter the while loop, you only know the following things:
Your linked list has at least two elements
h.element != sv or h.next == None
The current node is not None
The node following the current node (start.next), however, may be None at some point - when you reach the end of your linked list. Therefore, you are trying to access a node that doesn't exist.
Here's how I would have done it. I haven't tested this, but I'm pretty sure this works:
def moveSmallest(head):
if head is None or head.next is None:
return head
# First, determine the smallest element.
# To do this, we need to visit each node once (except the head).
# Create a cursor that "iterates" through the nodes
# (The cursor can start at the 2nd element because we're guaranteed the head will never have the smallest element.)
cursor = head.next
current_minimum = head.next.element
while cursor is not None:
if current_minimum > cursor.element:
# We've found the new minimum.
current_minimum = cursor.element
cursor = cursor.next
# At this point, current_minimum is the smallest element.
# Next, go through the linked list again until right before we reach the node with the smallest element.
cursor = head
while cursor.next is not None:
if cursor.next.element == current_minimum:
# We want to reconnect the arrows.
if cursor.next.next is None:
cursor.next = None
else:
cursor.next = cursor.next.next
break
new_node = Node(current_minimum, head)
head = new_node
return head
When the remove_from_tail() method is called, the last element in the linked list is removed from the linked list. Your solution to this exercise will be a minimal implementation of the LinkedList class that contains the following methods: init(), print_all(), add() and remove_from_tail(). To complete the remove_from_tail() method, it might be useful to create a loop and use a "curr" reference to locate the last element in the list, but at the same time keep a "prev" reference to the previous Node in the chain. Once you have reached the end of the list, you can set the "next" field of the "prev" pointer to None to remove the last element. You can assume that there will be at least one element in the list when remove_from_tail() is called - however, if there is only one element, then you will need to set head to None when that element is removed.
EDIT:
I have change my code and got things right, however, there are still small things with error, and I can't seems to figure out why. This is my new code:
def remove_from_tail(self):
current = self.head
previous = current
while current.get_next() != None:
previous = current
current = current.get_next()
previous.set_next(None)
return current.get_data()
The error that has to be fixed:Sample2
The while-loop conditional handles only multiple-item lists. Try adding a condition to check for one-item lists before the while loop:
# Check for an empty list
...
# Check for one-item list
if current.get_next() == None:
data = current.get_data()
self.head = None
return data
# Multi item list
...
I'm having trouble trying to implement a linked List without using classes(we're not there yet in my course), and google hasn't helpful at all. Every linked list example uses classes, which I haven't covered. I can create a linked list that adds a value to the beginning of the linked list, but I don't know how to traverse the list and add value after a specific node. Any help would be appreciated. The hardest part for me is figuring out how to traverse the list.
def addValue(linkedSet, value):
"""
Adds a new element to a set.
Parameters:
the set to be changed (address of the first node)
the new value to add to the set
Return result: pointer to the head of the modified set. This is
usually the same as the linkedSet parameter, unless the value
added is less than any value already in the set.
If the value is already in the set, return the set unchanged.
This is not an error.
"""
newNode={}
newNode['data']=value
node=linkedSet
if linkedSet==None:
newNode['next']=None
return newNode
if member(linkedSet,value)==True:
return linkedSet
elif linkedSet['next']==None:
newNode['next']=None
linkedSet['next']=newNode
elif linkedSet['next']!=None:
return linkedSet
Just as a general outline of what I think your addValue() function might look like...
def addValue(linkedSet, value):
newNode={
'data': value,
'next': None
}
# if linkedSet is None, then you can just return this newNode
# if linkedSet isnt None...
# if linkedSets next is None, then it should just point to this newNode
# (append)
# otherwise, you should set its current next to the next of this newnode,
# and then set its next to this newNode (insert)
This is for a general linked list. It seems like you are suggesting that yours is a more specialized version that maintains a value sort, and always expects to be passed the head node of the list. Yours would require constant looping over each 'next' until it found one where the value was greater than the current, and then insert itself by shifting around the 'next' references of the following (and possibly previous) elements.
unless the value
added is less than any value already in the set sounds like this list is supposed to be sorted. So you go through the list, find the first item larger than your value and splice it in there.
You traverse the list by keeping track of the current node:
def addValue(linkedSet, value):
newNode={}
newNode['data']=value
newNode['next'] = None
#traverse list
current = linkedSet
while True:
if current['value'] == value:
return linkedSet # it was already in that list
if current['value'] > value:
# new node is the new head
newNode['next'] = linkedSet
return newNode # new head
if current['next'] is None:
# new tail
current['next'] = new_node
return linkedSet
if current['next']['value'] > value:
# new node belongs here, splice it in
next_node = current['next']
current['next'] = newNode
newNode['next'] = next_node
return linkedSet
# didnt return so far, try the next element:
current = current['next']
How about using dictionary as linked list descriptor?
Something like:
linkedSet = {'first':firstNode, 'last':lastNode}
Then when you need to travers you could always start from first node,
and when you need to add you have your end node.