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
...
Related
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
I'm trying to understand what the following function does, and in specific what does the if part is doing:
def remove(items, value):
new_items = []
found = False
for item in items:
if not found and item == value:
found = True
continue
new_items.append(item)
if not found :
raise ValueError('list.remove(x): x not in list')
return new_items
The statement if not found and item == value: and the trick of variable found . can someone specifically explain it?
Thanks, Now I understand the example code snippet above. And I can write code to implement my idea
My idea is to first make sure the value is in the initial list . then compare every item with that value, add the item which doesn't satisfy condition item != value to a new list new_items, finally return the new list.
def remove(items, value):
new_items = []
for item in items:
if item == value :
continue
else :
new_items.append(item)
if len(items) == len(new_items):
print("This value is not in the list")
return new_items
found is just a flag; while it's False (not found is True), you're checking each item against the target value. When you find a match, you set found to True, and bypass the item that matched (continue skips the rest of the body of the loop, returning to the top of the loop immediately, so append isn't called).
After that, not found is always False, and since and is a short-circuiting test, if the left hand side is False, then the right hand side isn't even checked. From there on, you just append all remaining items as you go. By using the flag and checking it first, you:
Avoid removing more than one copy of value from the newly created list
Avoid the work of comparing items once you've found a match (testing not somebool is the cheapest test available in Python beyond testing a compile time constant), speeding up the code a bit
Since found is initialized to be False it means that not found is evaluated to True, so while we're iterating the items and until we've found the item we're looking for, we'll compare each item == value and if it evaluates to True we'll enter the if body and execute two things:
modify the value of found to True: which means that from now on
we'll never enter that if block again
continue we'll "jump" over the part that adds this item that we
found
To sum it up: when we'll run into the first occurrence of value during iteration, we'll flip the value of the flag found and we'll skip the part that adds it to the new list. This will result in adding all the items but this one to the new-list.
I need to create a dictionary where will be key a string and a value a list. The trick is I need to do it in a loop.
My minimalised code looks like this at the moment:
for elem in xmlTree.iter():
# skipping root element
if elem.tag == xmlTree.getroot().tag:
continue
# this is supposed to be my temporary list
tmpList = []
for child in elem:
tableWColumns[elem.tag] = tmpList.append(child.tag)
print(tableWColumns)
This prints only the list created in the last iteration.
Problem apparently lies in the fact that whenever I change the list, all of its references are changed as well. I Googled that. What I haven't Googled though is the way how can I deal with it when using a loop.
The solution I am supposed to use when I want to keep the list is to copy it to some other list and then I can change the original one without losing data. What I don't know is how do I do it, when I basically need to do this dynamically.
Also I am limited to use of standard libraries only.
The problem is because of that you are creating the tmpList = [] list in each iteration and put it [].So python replace the new with older in each iteration, thus you see the last iteration result in your list.
Instead you can use collections.defaultdict :
from collections import defaultdict
d=defaultdict(list)
for elem in xmlTree.iter():
# skipping root element
if elem.tag == xmlTree.getroot().tag:
continue
# this is supposed to be my temporary list
for child in elem:
d[elem.tag].append(child.tag)
print(tableWColumns)
Or you can use dict.setdefault method :
d={}
for elem in xmlTree.iter():
# skipping root element
if elem.tag == xmlTree.getroot().tag:
continue
# this is supposed to be my temporary list
for child in elem:
d.setdefault(elem.tag,[]).append(child.tag)
print(tableWColumns)
Also note as #abarnert says tmpList.append(child.tag) will return None.so after assignment actually python will assign None to tableWColumns[elem.tag].
The big problem here is that tmpList.append(child.tag) returns None. In fact, almost all mutating methods in Python return None.
To fix that, you can either do the mutation, then insert the value in a separate statement:
for child in elem:
tmpList.append(child.tag)
tableWColumns[elem.tag] = tmpList
… or not try to mutate the list in the first place. For example
tableWColumns[elem.tag] = tmpList + [child.tag for child in elem]
That will get rid of your all-values-are-None problem, but then you've got a new problem. If any tag appears more than once, you're only going to get the children from the last copy of that tag, not from all copies. That's because you build a new list each time, and reassign tableWColumns[elem.tag] to that new list, instead of modifying whatever was there.
To solve that problem, you need to fetch the existing value into tmpList instead of creating a new one:
tmpList = tableWColumns.get(elem.tag, [])
tableWColumns[elem.tag] = tmpList + [child.tag for child in elem]
Or, as Kasra's answer says, you can simplify this by using a defaultdict or the setdefault method.
I've been completely stumped on this one:
I have the following python code:
def remove(self, widgets):
for widget in widgets:
widget_found = False
for widget_sig in self.widgets:
if widget_sig.id == widget:
#remove all objects from selected widget
widget_found = True
to_remove = widget_sig.objs
for obj in to_remove:
#objs are all intances of oo_canvas classes
obj.destroy()
self._build(widget, obj)
if not widget_found:
#if we iterated through the entire list and still couldn't find anything
raise mockingbird_errs.InternalMockingbirdError("The requested widget was not registered with this builder: "+str(widget))
This should be pretty straight forward. The thing is, it never iterates through to_remove correctly. For some reason, it skips every other element. Even more baffling, is if I have it print the length of to_remove before and after the for loop, it prints 254 and 127. Huh? As far as I know, iterating through a list does not involve deleting every other element.
Am I missing something straightforward? What on earth is going on?
... it skips every other element.
That's because you keep deleting them, shortening the list by 1. And then you move on to the next index. Either work backwards, or iterate over a copy of the 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.