You should do val = val.next instead of val.next = val.next.next. The way you're doing it, the list will be truncated to a single element when you call count_length. Because you do count_length at the top of kth_to_last, by the time you get around to walking your list (where your 'hi' is), the list has already been reduced to a single node.
Remember, a linked list is a structure where each node's next property is a pointer to the next node. Your code is modifying the value of next, which is changing the structure of your linked list.
When you process a linked list (in count_length, or in kth_to_last), what you want to do is point yourself at each node in turn. You're not trying to modify the nodes themselves, so you won't assign to their value or next attributes. The way to do this is to change what your pointer (val) is pointing at, and the thing that you want it to point at next is the next node along. Therefore:
val = ll.head
while val is not None:
# do something with val here
val = val.next
Answer from wildwilhelm on Stack OverflowYou're doing way more work than you have to. Once you've implemented __iter__, the rest falls into place. You can use it to implement pretty much all your other functions, like get_node, __str__ or __repr__, etc.
class Node:
def __init__(self, value):
self.value = value
self.next = None
def __str__(self):
return str(self.value)
class LinkedList:
def __init__(self):
self.head = None
def add(self, value):
if self.head is None:
self.head = Node(value)
else:
for cursor in self:
pass
cursor.next = Node(value)
return self
def get_node(self, node_index):
for index, node in enumerate(self):
if index == node_index:
break
else:
return None
return node
def __str__(self):
return " -> ".join(map(str, self))
def __iter__(self):
cursor = self.head
while cursor is not None:
yield cursor
cursor = cursor.next
ll = LinkedList().add(1).add(2).add(3)
print(ll)
for node_index in 0, 1, 2, 3:
print("The node at index {} is {}".format(node_index, ll.get_node(node_index)))
Output:
1 -> 2 -> 3
The node at index 0 is 1
The node at index 1 is 2
The node at index 2 is 3
The node at index 3 is None
>>>
ThisgetNode()also works:
def getNode(self,loc):
it = iter(self)
for i in range(loc):
next(it)
return next(it)
Python stacked linked list - Stack Overflow
Error when using __iter__ and __next__ with a Python linked list? - Stack Overflow
Python linked list - Code Review Stack Exchange
python - Linked list: While fast and fast.next - Stack Overflow
Confession: I've never actually written a linked list. At a cursory glance, this implementation looks fine, but I don't know any of the common mistakes. Would be good for somebody who knows more about them (perhaps even an actual interviewer) to give it the stamp of approval.
Working from top-to-bottom:
There are no docstrings or comments anywhere in this code. I'm aware that's not always possible in an interview situation – but since you're writing this in advance, you can probably do it (after the fact, if nothing else).
It makes the code easier to read, review and maintain. It's also a good way to expose code that doesn't really make sense.
The
__repr__of a class is usually a string that could be eval’d to get an equivalent object. What you’ve written for Node is more like what I’d expect for__str__. More like:def __repr__(self): return '%s(data=%r, next_node=%r)' % (self.__class__.__name__, self.data, self.next)In the prepend method of LinkedList, you're not taking advantage of the constructor API you've defined for Node. You could write it more compactly as:
def prepend(self, data): new_head = Node(data, next_node=self.head) self.head = new_headThere's also a typo – theIn which case this becomes a one liner:new_head2variable isn't defined. Perhaps you meantself.head = new_head?def prepend(self, data): self.head = Node(data, next_node=self.head)In general, there's a lot of similar-looking code that strides back and forth through your linked lists. Lots of
iter_nodes and positions and the like. Would be good to cut that down.Remembering that I know nothing about linked lists, I think it might be helpful to define a
__len__method on your LinkedList class. Combined with__getitem__, this could simplify your insert() and delete() methods.Something like:
def insert(self, position, data): # This is incomplete -- you'll need to handle KeyErrors and # the like. To mimic the insert() method on __builtin__.list, # if position > len(self), just stick it at the end. prev_node = self[position] next_node = self[position + 1] new_node = Node(data, next_node=next_node) prev_node.next = new_nodeThis then drastically simplifies the code for prepend() and append():
def prepend(self, data): self.insert(position=0, data=data) def append(self, data): # Probably want to check I haven't introduced an off-by-one # error here. self.insert(position=len(self), data=data)If nothing else, it seems like you could make more use of your
__iter__method, which comes right at the end and almost seems like an afterthought. That could be really useful. Some examples:def __eq__(self, other): # other is the standard arg here if len(self) != len(other): return False for node_s, node_o in zip(self, other): if node_s != node_o: return False return TrueI would have your
__getitem__method raise an IndexError if I search off the end of the list, or before I've put in any data. This is a better fit with the semantics of the builtin list. And again, you can rewrite it to take advantage of__iter__:def __getitem__(self, position): if not self.head or len(self) < position: raise IndexError for idx, node in self: if idx == position: return nodeNote also that I'm returning the Node instance, not just the data from that node.
Include an example. Again, caveat that I haven't done this sort of interview much, so don't know if this is even possible, but a little snippet showing how this list is supposed to be used would be helpful.
It shows off the API, how you think the class should be used, and it's a good way to spot blatantly silly interfaces.
It also helps if there's a bug in your code – such as the
next_head2typo – because I can see where you were aiming.
And a few quick nitpicks:
Don't put spaces around default arguments, for example in the
__init__for your Node object.Single line between methods on the same class, for example in LinkedList.
Compare to None with
if foo is [not] None, for example in the append method of LinkedList.
Adding on to alexwlchan's notes:
PEP8 suggests surrounding operators with a space, so pos -= 1 rather than pos-=1.
You've implemented __iter__, so LinkedList.__repr__ can be a one-liner:
def __repr__(self):
return "[%s]" % ", ".join(map(str, self))
although it's really more of a __str__, an informal, readable stringification.
There are also a lot of very similar loops that could be abstracted internally.
I noticed that if I use
while fast.nextinstead ofwhile fast and fast.nextfor the loop, I got the same results.
This will work for input lists that have an odd number of nodes, but it will fail withe input lists that have an even number of nodes -- the trivial example being an empty list (with 0 nodes).
May I ask why I should use both
fast and fast.nextto stop the while loop?
In each iteration a pair of nodes is traversed, so in the case of an even number of nodes, there will come a situation where fast is None at the moment the while condition is evaluated. If you then only check fast.next -- without first ensuring that fast is really a node -- it will raise an error, as this really means you're doing None.next which of course doesn't work.
From my understanding, if
fast.next is None,fastis always none, is this correct?
No, this is not correct. If fast.next is None then this implies that fast is a node with a next attribute, so certainly fast is then not None. But fast.next can produce an error when fast is None. It is for that reason that before evaluating fast.next one must be sure that fast is a node and not None.
If the condition is fast and fast.next and it happens that fast is None then the evaluation will short-circuit and fast.next will not be evaluated at all (and that's what you want to avoid an error). This is because the and operation is already sure to evaluate to a falsy value when the left-side operand (fast) has been evaluated to be None.
As you traverse the linked list, and have a fast pointer that advances to the current node's next to next node, you have to make that check. Since the last node will have None (null) value for its next member variable, and if accessed simply as fast.next.next it leads to null pointer exception(NPE). To avoid it, your loop condition must be as you have it right now.
Just as mentioned by @abarnert , you always need a __iter__ method for the iterator class.
class LinkedListIterator:
def __init__(self, head):
self.current = head
def __iter__(self):
return self
def __next__(self):
if not self.current:
raise StopIteration
else:
item = self.current.get_data()
self.current = self.current.get_next()
return item
class LinkedList:
def __init__(self):
self.head = None
def __iter__(self):
return LinkedListIterator(self.head)
def add(self, item):
new_node = Node(item)
new_node.set_next(self.head)
self.head = new_node
Now that your class is iterable, you can use "for...in" loop:
test_list = LinkedList()
test_list.add(1)
test_list.add(2)
test_list.add(3)
for item in test_list:
print(item)
Please check the tutorial here.
You can use the yield keyword to make a generator so you dont have to implement __next__()
class LinkedList:
def __init__(self):
self.head = None
def __iter__(self):
curNode = self.head
while curNode:
yield curNode.value
curNode = curNode.nextNode
def add(self, item):
new_node = Node(item)
new_node.set_next(self.head)
self.head = new_node
And in your print_iterator_explicit function you can do it like this
def print_iterator_explicit(items):
iterator = iter(ll)
while True:
try:
print(next(iterator))
except StopIteration:
break
Check out this link for more information on iterators and generators: Iterators and generators
A little side note: your head variable is behaving like a tail. In a linked list the first node is called the head and the last is called the tail
The del current node and return node_A.value, node_B.value, node_C.value commands should belong to the pop() function, so they should be indented. But anyway the del current node doesn't work for me. Instead you could write current_node.value = None but then you still return all 3 node values so the result would be 1,2,None.
I would rather write the pop() function inside the class and add another printlist() function to the class as well. The pop() function just removes the last element from the list (changes the next attribute to None for the 2nd last element in the list) and doesn't print or return anything. The printlist() function iterates through the list and prints out all elements (while there are next elements). Here is my code:
class LinkedList:
def __init__(self, value):
self.value = value
self.next = None
def pop(self):
current_node = self
while current_node.next:
if current_node.next.next == None:
current_node.next = None
else:
current_node = current_node.next
def printlist(self):
current_node = self
lst = [current_node.value]
while current_node.next:
current_node = current_node.next
lst.append(current_node.value)
print lst
node_A = LinkedList(1)
node_B = LinkedList(2)
node_C = LinkedList(3)
node_A.next = node_B
node_B.next = node_C
try:
node_A.pop()
node_A.printlist()
except NameError:
pass
If I run this, the result is [1,2]. If I remove the node_A.pop() I get [1,2,3]. If I write another node_A.pop() then result is [1].
I guess I have found the issue with your logic, so based on the code provided it seems that pop function doesn't return anything, may be it's just formatting or something else.
But here is the correct version of your code, where I just delete the last node in the pop method and I call another method called listValues which returns me with the node values that exist in the linked list after pop
Look at the below implementation for a clearer view.
class LinkedList:
def __init__(self, value):
self.value = value
self.next = None
node_A = LinkedList(1)
node_B = LinkedList(2)
node_C = LinkedList(3)
node_A.next = node_B
node_B.next = node_C
def pop(head):
current_node = head
while current_node.next:
if current_node.next == None:
del current_node
break
else:
current_node = current_node.next
def listValues(head):
values = []
current_node = head
while current_node.next:
values.append(current_node.value)
current_node = current_node.next
return values
try:
pop(node_A)
print(listValues(node_A))
except NameError:
pass
Hope this helps!
For some needs, a deque may also be useful. You can add and remove items on both ends of a deque at O(1) cost.
from collections import deque
d = deque([1,2,3,4])
print d
for x in d:
print x
print d.pop(), d
Here is some list functions based on Martin v. Löwis's representation:
cons = lambda el, lst: (el, lst)
mklist = lambda *args: reduce(lambda lst, el: cons(el, lst), reversed(args), None)
car = lambda lst: lst[0] if lst else lst
cdr = lambda lst: lst[1] if lst else lst
nth = lambda n, lst: nth(n-1, cdr(lst)) if n > 0 else car(lst)
length = lambda lst, count=0: length(cdr(lst), count+1) if lst else count
begin = lambda *args: args[-1]
display = lambda lst: begin(w("%s " % car(lst)), display(cdr(lst))) if lst else w("nil\n")
where w = sys.stdout.write
Although doubly linked lists are famously used in Raymond Hettinger's ordered set recipe, singly linked lists have no practical value in Python.
I've never used a singly linked list in Python for any problem except educational.
Thomas Watnedal suggested a good educational resource How to Think Like a Computer Scientist, Chapter 17: Linked lists:
A linked list is either:
- the empty list, represented by None, or
a node that contains a cargo object and a reference to a linked list.
class Node: def __init__(self, cargo=None, next=None): self.car = cargo self.cdr = next def __str__(self): return str(self.car) def display(lst): if lst: w("%s " % lst) display(lst.cdr) else: w("nil\n")
Notes on LinkedList:
- The import is unused.
- It should allow creation of an empty list.
- Normally a linked list inserts items after the last item. Maybe I'm confused by the way
insertworks, but it looks like in your caseheadis always the last inserted entry in the list, and the list is traversed fromheadbackwards through history using.next. deleteshould usesearch.
Notes on Stack:
self.datashould beself.entriesor something else descriptive.prntshould beas_stringor even__str__.int(val)does not check whether something is an integer, it just tries to convert a value to an integer.+,-,*and/are arithmetic, not binary, operators.- In Python 3 mathematical operators are modeled as functions.
is_integer,is_binary_operatorandpostfixEvalshould not be part ofStack- they are not fundamental to the stack in any way.
def is_integer(val):
try:
int(val)
return True
except ValueError:
return False
Should be written:
def is_integer(val):
try:
int(val)
except ValueError:
return False
return True
This is cleaner because what may trigger the exception is not the return statement but when int() tries to convert val. Besides, maybe what you really are looking for is:
import numbers
def is_integer(val):
return isinstance(val, numbers.Integral)
This way, you do not have to worry about exceptions since they are managed under the hood and, I think that is also the data type you want to deal with.
def prnt(self): print self.data
A stack has push(), pop() and size() operations, but nothing like prnt(). If you need the functionality prnt() is doing, take advantage of the Python __repr__() magic method instead:
def __repr__(self):
return '{} '.format(self.data)
for the method my thought process is...
What method? get_position? insert? delete?
As @JacobIRR suggested, adding a way of printing your linked list can be helpful. Take a look:
class Element:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, value):
element = Element(value)
if self.head is None:
self.head = element
return
cursor = self.head
while cursor.next is not None:
cursor = cursor.next
cursor.next = element
def __str__(self):
values = []
cursor = self.head
while cursor is not None:
values.append(cursor.value)
cursor = cursor.next
return " -> ".join(values)
def main():
linked_list = LinkedList()
linked_list.append("Foo")
linked_list.append("Bar")
linked_list.append("Fizz")
linked_list.append("Buzz")
print(linked_list)
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
Output:
Foo -> Bar -> Fizz -> Buzz
All you need to do:
Firstly, try to visualize what will be happening while changing this state to that, or like- write the whole visualization on a paper or even in any online software to understand the changes.
Lastly/Finally, make sure that you know the core concept of linked-lists and do some tricky, bunch of different operation with it. Or, you may search on Google for a couple of resources.
Well, here is the solution I did for your problem:
class Element(object):
def __init__(self, value):
self.value = value
self.next = None
class LinkedList(object):
def __init__(self, head=None):
self.head = head
def append(self, new_element):
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new_element
else:
self.head = new_element
def get_position(self, position):
counter = 1
current = self.head
if position < 1:
return None
while current and counter <= position:
if counter == position:
return current
current = current.next
counter += 1
return None
def insert(self, new_element, position):
counter = 1
current = self.head
if position > 1:
while current and counter < position:
if counter == position - 1:
new_element.next = current.next
current.next = new_element
current = current.next
counter += 1
elif position == 1:
new_element.next = self.head
self.head = new_element
def delete(self, value):
current = self.head
previous = None
while current.value != value and current.next:
previous = current
current = current.next
if current.value == value:
if previous:
previous.next = current.next
else:
self.head = current.next
# Test cases
# Set up some Elements
e1 = Element(1)
e2 = Element(2)
e3 = Element(3)
e4 = Element(4)
# Start setting up a LinkedList
ll = LinkedList(e1)
ll.append(e2)
ll.append(e3)
# Test get_position
# Should print 3
print(ll.head.next.next.value)
# Should also print 3
print(ll.get_position(3).value)
# Test insert
ll.insert(e4,3)
# Should print 4 now
print(ll.get_position(3).value)
# Test delete
ll.delete(1)
# Should print 2 now
print(ll.get_position(1).value)
# Should print 4 now
print(ll.get_position(2).value)
# Should print 3 now
print(ll.get_position(3).value)
Again, any further problem; take a paper, write the code and visualize what's happening.
I was trying the Merge Two Sorted Lists question from Leetcode and had a pretty fundamental doubt. This is the solution of the code in Python:
def mergeTwoLists(self, list1, list2):
dummy = ListNode()
tail = dummy
while list1 and list2:
if list1.val < list2.val:
tail.next = list1
list1 = list1.next
else:
tail.next = list2
list2 = list2.next
tail = tail.next
if list1:
tail.next = list1
elif list2:
tail.next = list2
return dummy.next
Here, we are returning dummy.next as a representation of the final merged linked list but I thought that the next attribute pointed to only the next node? My understanding was that we would need to return tail since that represents the list node as a whole?