I have to do the following for my homework:
Suppose that your linked list is not empty, and is pointed to by the variable head. Write a method called findMin() that goes through the list and finds the least value (you can compare strings just like numbers) and returns that.
Suppose that your linked list is not empty, and is pointed to by the variable head. Write a method called getLast() that goes through the list and returns the last thing in the list. This is the value of the last node in the linked list chain.
Finish the append method. It runs to the end and attaches the new node to the last existing nodes in the chain. If there are no nodes in the chain yet, it sets self.head to that node. Beware! This is tricky! You might consult your textbook.
I attempted to solve the first one and I am just lost, I don't know if I am messing up the class structure or what (I just learned classes like 3 days ago)
Here's my attempt...
class LinkedList:
class Node:
def __init__(self,value):
self.value = value
self.next = none
def __init__(self):
self.head = None
def findMin(self):
currentNode = self.head
minNode = self.head
while currentNode != none:
if currentNode.next < currentNode:
minNode = currentNode
currentNode = currentNode.next
return minNode
As #mgilson mentioned in comments, there are a number of things wrong, and not all were listed.
I think you would benefit a lot from writing (in comments, why not) what you think each line is doing.
Let's start with
currentNode = self.head
I think this is trying to say "let's start at the head of the list, by setting currentNode to point to that".
As written, this appears to be accessing a member variable of the current node, called 'head'. But the Node class definition doesn't have a defined member called head! And... why do you need to do that? You are told "the current node is the head"!
So you probably mean
currentNode = self # start at the head of the list
Next:
minNode = self.head
This is saying "The node with the current known minimum is stored in this one"
As before, you probably mean:
minNode = self # The head currently has the minimum we know about
Then:
while currentNode != none:
First, if you use a syntax highlighting editor, straight away it will tell you that 'None' has a capital 'N'.
No other problems here.
Then:
if currentNode.next < currentNode:
minNode = currentNode
currentNode = currentNode.next
This is trying to say "if the value of the next node is less than the value of this one, then the minimum is now ..." ... actually what? It's saying it's the current one! But it's not: if this if statement is true, then the next one contains the minimum! And hang on, shouldn't we be comparing with minNode, not currentNode?
Seems like you mean
if currentNode.value < minNode.value:
minNode = currentNode # this node is now the smallest we know about
and this next line needs to be outside the if loop, because it moves us on to the next node:
currentNode = currentNode.next # move on to the next node
Phew, nearly there: now we have to return the minimum value not, the node that has the minimum value (read the instructions carefullly.
return minNode.value
HTH
Ok, let's do this homework!
Let Node be a list cell. It has two fields value and next (also called car/cdr or head/tail in functional languages).
class Node:
def __init__(self, value):
self.value = value
self.next = None
append(node, other) can be defined as follows: if node has no "next" node (i.e. it is the last), attach other right to this node. Otherwise, take the "next" node, and append (recursively) other to that one:
def append(self, other):
if self.next:
self.next.append(other)
else:
self.next = other
Now let's define two essential functionals: map and reduce. map applies a function to each node in order and returns the list of results:
def map(self, fn):
r = [fn(self.value)]
if self.next:
r += self.next.map(fn)
return r
reduce applies a function to each node and combines results into a single value:
def reduce(self, fn, r=None):
if r is None:
r = self.value
else:
r = fn(r, self.value)
if self.next:
return self.next.reduce(fn, r)
return r
Now you're ready for the homework.
Create a list:
lst = Node(1)
lst.append(Node(8))
lst.append(Node(3))
lst.append(Node(7))
print all values:
print lst.map(lambda x: x)
find the last value:
print lst.reduce(lambda r, x: x)
find the max value:
print lst.reduce(max)
etc
Let us know if you have questions.
Related
I am trying to create an Insert method which takes a parameter (position) and inserts a Node into a linkedlist at that given position. Thus, the new value would be the value of the parameter (val) and then the next node would take the original value and so forth. This also needs to utilize recursion.
I am currently trying to mess around with the conditionals and first say that if our index matches our desired position, we can set a new_node to our current node and then set our current node to a Node with our desired value. Then our next node can take the value of current node. After that, I have a conditional where if our index is greater, I set the next node to our current node.
I am currently not seeing the insertion change the values in the linkedlist and also getting an infinite loop, which I feel like has to do with when we reach the end of the LinkedList, it is not ending properly. I'd appreciate if anyone has any suggestions of how I could go about fixing this or if my logic is just wrong.
def insert(self, val, position, current=None, index=0, new_node=None):
if self._head is None:
self._head = Node(val)
return
if current is None:
current = self._head
if position > index and current.next is None:
current.next = Node(val)
return
if position == index and current is not None:
new_node = current.next
self._head = Node(val)
if position > index and current is not None:
new_node = current.next
self._head = current
if current is None:
return
self.insert(val, position, current.next, index + 1)
This case seems wrong:
if position == index and current is not None:
new_node = current.next
self._head = Node(val)
This would be the point where you'd want to insert the new node at current. Instead, you set a new_node variable (which does nothing, because you don't do anything else with it), and then you create a new self._head (which effectively deletes the rest of the list).
Your recursion never stops because on each recursion you increment index, but your base case is based on position > index:
# checking that we're at the end of the list
# AND position is ahead of index
if position > index and current.next is None:
current.next = Node(val)
return
self.insert(val, position, current.next, index + 1)
# next moves forward, index moves forward
Recursion should always move you closer to your base case, which means that either position should be increasing or index should be decreasing, but instead index is increasing while position stays the same, which means it's never possible to satisfy your base case.
I might write the function like this, with fewer parameters and only two base cases:
def insert(self, val, index=0, current=None):
if current is None:
current = self._head
if index <= 0 or self._head is None:
# Insert new val as head.
new_node = Node(val)
new_node.next = self._head
self._head = new_node
elif index == 1 or current.next is None:
# Insert new val as current.next.
new_node = Node(val)
new_node.next = current.next
current.next = new_node
else:
# Move down the list.
self.insert(val, index - 1, current.next)
In this implementation, index represents the position relative to current where we want to insert the new node, i.e. if index == 0 we want the new node to take the place of current, and if index == 1 we want the new node to take the place of current.next.
Our first base case checks for index == 0 on the initial call, in which case we want to replace self._head. The next base case checks for index == 1, in which case we want to replace current.next. Note that if current != self._head and index == 0 we'd be stuck because we don't have a pointer to the previous node in order to be able to replace current in the list, so that's why we want to do the current.next insertion at index == 1, before we advance to the next node.
In both base cases we also have an or that covers the case where we're at the end of the list (including the case where the list is empty) and it doesn't make sense to iterate forward regardless of what index is.
When we recurse, we move current forward by one spot, and decrement index by one, since we're one position closer to the desired location. Eventually index will reach 1, or we'll reach the end of the list, at which point we're done and we stop recursing.
# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev=ListNode(-1,head)
curr=head
dummy=head
while dummy.next:
curr.next=prev
prev=dummy
dummy=dummy.next
curr=dummy
return prev
I created three nodes, I used the prev and curr node for reversing and the dummy node for traversing ahead in the original linked list but I am getting time limit exceeded. I would like to know my logical error in this method
Some issues:
In the loop you modify the node's next attribute before saving the original next reference. So once that is done, you have lost all possibility to move forward in list, and dummy=dummy.next will now walk back since at the start of the iteration, dummy was equal to curr.
It is undesired to create a new node with value. Your code would link back to it in the first iteration of the loop. And because of the first problem, dummy becomes prev, which has a next reference to where you came from, creating an infinite loop. Instead of this -1 Node, just initialise prev as None.
The while condition is wrong. The loop should continue until you reach the very last node, so when curr is None.
Not a major issue, but why call that node reference dummy? There is nothing dummy about it. Use a name that describes what it references, for instance nextNode or nxt for short.
Correction:
class Solution:
def reverseList(self, head):
prev=None # Don't create a new node
curr=head
while curr: # Continue until the *last* node
nxt=curr.next # Save the next reference
curr.next=prev
prev=curr
curr=nxt # ... so you can move ahead
return prev
I am newly learning about Linked Lists and my assigment requires me to make a function that returns the lowest odd number...and I think I have done that in my get_min_odd function.
I believe my code is only checking the first and second element of the linked list so my question is how can I iterate through a linked list to find the lowest odd number? I would think a for loop but I don't understand what list I'm iterating through...which brings up another question, where are the elements in a linked list stored if not in a list, array, string, etc.?
class LinkedList:
def __init__(self):
self.head = None
#def.....
def add_all(self, a_list):
newNode = Node(a_list)
newNode.next = self.head
self.head = newNode
for i in a_list:
self.next = i
def add_all(self, a_list):
for i in range(len(a_list)):
self.add(a_list[i])
def get_min_odd(self):
lst = []
if self.head.data % 2 == 1:
lst.append(self.head.data)
elif self.head.next.data % 2 == 1:
lst.append(self.head.next.data)
else:
return 999
return min(lst)
my_list = LinkedList()
my_list.add_all([1, 4, -3, 6, 9, 2, 10001, 25, 19, 20])
print(my_list.get_min_odd())
A few issues:
You have two methods that are called add_all. This means the first one will be lost. You actually need an add method instead of that first add_all. And it should not take a list as value, but just a single numeric value. That method should not have to loop (Moreover, assigning i to the same next attribute over and over again makes no sense).
get_min_odd is indeed too much fixed on the first and second node. They might not even exist when the list is short or empty. To loop over a linked list, you need a name that first equals the head node, but then traverses along the next attributes to the next node, and then the next, ... until it reaches the end.
get_min_odd should not create a list with values. That defeats the purpose of a linked linked list. Instead that code should immediately update the minimum it has while traversing the linked list.
Here is the updated code for the two methods that needed correction:
def add(self, value): # name and arg name correction
newNode = Node(value)
newNode.next = self.head
self.head = newNode
and:
def get_min_odd(self):
result = None
node = self.head
while node: # as long as the end of the list is not encountered...
if node.data % 2 == 1:
# adjust the result to the minimum data encountered so far
result = node.data if result is None else min(result, node.data)
node = node.next # traverse to next node
return result
I am trying to solve the following problem on algoexpert:
Shift Linked List
Write a function that takes in the head of a Singly Linked List and an integer
k, shifts the list in place (i.e., doesn't create a brand new
list) by k positions, and returns its new head.
Shifting a Linked List means moving its nodes forward or backward and wrapping
them around the list where appropriate. For example, shifting a Linked List
forward by one position would make its tail become the new head of the linked
list.
Whether nodes are moved forward or backward is determined by whether
k is positive or negative.
Each LinkedList node has an integer value as well as
a next node pointing to the next node in the list or to
None / null if it's the tail of the list.
You can assume that the input Linked List will always have at least one node;
in other words, the head will never be None / null.
Sample Input
head = 0 -> 1 -> 2 -> 3 -> 4 -> 5 // the head node with value 0
k = 2
Sample Output
4 -> 5 -> 0 -> 1 -> 2 -> 3 // the new head node with value 4
The outline that the problem gives for the code is the following:
class LinkedList:
def __init__(self, value):
self.value = value
self.next = None
def shiftLinkedList(head, k):
#Write your code here.
pass
I suppose my background on linked list is very limited because from every resource I've read on linked lists, the general outline for it requires the node class and to have all the methods for rotating or shifting inside the LinkedList class.
I assume the head parameter for the function is going to be an integer that denotes the position of the list but how do I refer the head back to the original list? I already have the code written in my Thonny editor but I wrote the function inside the LinkedList class and simply called for it after making my list.
For example:
class Node:
def __init__self(data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def push(self, newhead):
newnode = Node(new_data)
newnode.next = self.head
self.head = newnode
list1 = LinkedList()
list1.head = Node(1)
e2 = 2
e3 = 3
list1.head.next = e2
e2.next = e3
Only once I've established my linked list can I create a method inside the class to shift or rotate it. Or am I wrong?
I tried creating a function the way the algo wanted, but I am still stuck. I think what I am really confused about is whether the argument head is an integer or a LinkedList?
Here is my complete attempt:
class Node:
def __init__(self, data):
self.data = data #assign data
self.next = None #initialize next as null
class LinkedList:
#function to initalize the linked list object
def __init__(self):
self.head = None
def printList(self):
temp = self.head
while(temp):
print(temp.data)
temp = temp.next
def moveToFront(self):
tmp = self.head
sec_last = None
if not tmp or not tmp.next:
return
while tmp and tmp.next:
sec_last = tmp
tmp = tmp.next
sec_last.next = None
tmp.next = self.head
self.head = tmp
def shiftList(head, k):
if not head:
return
tmp = head
length = 1
while(temp.next != None):
tmp = tmp.next
length += 1
if(k>length):
k = k%length
k = length - k
if(k==0 or k==length):
return head
current = head
cmt = 1
while(cmt < k and current != None):
current = current.next
cmt += 1
if(current==None):
return head
kthnode = current
tmp.next = head
head = kthnode.next
kthnode.next = None
return head
I assume the head parameter for the function is going to be an integer that denotes the position of the list
No, the head of a list is a LinkedList instance. So head.value is the value of the first node in the list, and head.next is a reference to the second node in the list.
In your attempt you have changed the definition of LinkedList from the original, and created another class, called Node, which really is what LinkedList is supposed to be (except that you call a property data instead of value). It is understandable that you did this, as you wanted to have a kind of container class for the whole linked list, and reserve a separate class Node for what concerns a single node in that list. But this code challenge does not work with such a container class.
It just works with one class that represents a node, but through its next member the whole list is inferred from it. Moreover, they want the function to return a reference to the node that has become the head of the list once the shifting has completed. This is a different way of working than with a container class, in which you would mutate the head member, and would not return anything: the caller would just access the list through the modified head member.
So, what you intended to do is not inherently wrong, it just is not the data structure that this code challenge is working with. You should go with it.
what I am really confused about is whether the argument 'head' is an integer or a linkedlist
It is a node, but the list is inferred from it. It can be a bit confusing that they call their class LinkedList and not Node, but it is a matter of how you look at it.
So here is how you could solve it:
First find out what the last node is in the list. For this you will have to start from the head (you have nothing else) and step through the list until you bump into its end. Also maintain a counter so that at the end you know how many nodes there are in the list.
Then create a link from that tail node to the head node, so that the list now becomes circular: it has no end anymore
Find out which node comes k steps before the tail node in this cyclic list. As it is not possible to walk backwards in a list, you should actually walk size-k steps forward, and so you need the size of the list which you determined in the first step.
The node after that found node should become the head node.
Make that node itself the new tail node: break the link it has with the node after it (the new head).
Return the new head reference
One more thing should be done to protect this code against huge values for k. Let's say the list has 6 elements, and k is 600, then of course it makes no sense to run over the cyclic list 600 times, as we can predict that you'll end where you started! 600 is a multiple of 6... So to make this efficient, you need to reduce k to a number that is less than the size of the list. The formula for knowing how many steps forward you need to take is -k % size.
Here is the implementation of this idea:
def shiftLinkedList(head, k):
if not head:
return # Nothing to do
# Determine size of the list, and its tail node
size = 1
tail = head
while tail.next:
size += 1
tail = tail.next
# Temporarily make the list cyclic
tail.next = head
# Find out where to cut the cycle
for _ in range(-k % size):
tail = tail.next
head = tail.next
# Cut the cycle
tail.next = None
return head
I'm confused about how the while loop condition works in a linked list when checking for the middle node of a linked list
This is the correct code that I have for finding the middle node of a linked list
class Node(object):
def __init__(self, data):
self.data = data
self.next = None
class linkedList(object):
def __init__(self):
self.head = None
def append(self, data):
node = Node(data)
if self.head == None:
self.head = node
temp = self.head
while temp.next:
temp = temp.next
temp.next = node
def middle(self):
first = self.head
second = self.head
while second and second.next:
second = second.next.next
first = first.next
print(first.data)
If I change the while loop to
while second:
or
while second.next:
I receive an error that says
AttributeError: 'NoneType' object has no attribute 'next' on line 24
I'm just wondering why it's important to have both second and second.next
The solution works by using two pointers. First one takes 1 step at a time and second 2 steps at a time. However, in taking 2 steps there are two things to verify:
There is a next step that is valid
There is a step after the next step mentioned above
If you skip one check it will enter the loop but at the boundary condition it not find the next. To illustrate: If there are 4 nodes and you only check for second.next at the 3nd node you'll have second.next as valid and you'll enter the while loop but inside that you are directly accessing second.next.next
F,S
|
1 --> 2 --> 3 --> 4 --> None
For starters, your append method doesn't work, and gets stuck in an infinite while loop, since you don't exit out of append on adding the first element. The correct version is
def append(self, data):
node = Node(data)
if self.head == None:
self.head = node
return
else:
temp = self.head
while temp.next:
temp = temp.next
temp.next = node
As to your other question, we want to find the middle of the loop for both even and odd lists, the second.next covers the odd list case, and the second covers the even list case, since either the 2nd pointer will point to null, or it will be null itself, and if you use only one of them, you will get the error you described it, hence you need to have both conditions in the while loop