How do you create a LinkedList which contains loops? - python

I'm trying to come up with a test case for the solution given by hackerrank for detecting cycles in a linkedlist with python. The solution given by hackerrank is:
class Node(object):
def __init__(self, data = None, next_node = None):
self.data = data
self.next = next_node
def has_cycle(head):
fast = head;
while(fast != None and fast.next != None):
fast = fast.next.next;
head = head.next;
if(head == fast):
return True;
return False;
So I created what I thought was the following LinkedList
8 -> 7 -> 6 -> 5 -> 4 -> 3
^ |
| V
1 <-----------------2
Using this code:
Node_1 = Node(1)
Node_2 = Node(2, Node_1)
Node_3 = Node(3, Node_2)
Node_4 = Node(4, Node_3)
Node_5 = Node(5, Node_4)
Node_6 = Node(6, Node_5)
Node_7 = Node(7, Node_6)
Node_8 = Node(8, Node_7)
Node_1 = Node(1, Node_7)
But the results weren't what I expected:
print(has_cycle(Node_8)) # returns False
print(Node_2.next.next) # returns None
print(Node_1.next.data) # returns 7
This would work in C++, so it makes me think the problem is that I'm passing copies of objects rather than their pointers. If that's the case could someone point me to some material to learn about those sorts of concepts, please?
Also, how would I create the above mentioned test case?
Thanks!

The line:
Node_1 = Node(1, Node_7)
is creating a new node, it's not modifying the original Node_1 that's linked from Node_2. The lists you've created look like:
8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1
^
1 ---|
To create a cycle, you need a way to modify the next link of an existing node. Add this method to the Node class:
def set_next(self, next_node = None):
self.next = next_node
Then replace the last line with:
Node_1.set_next(Node_7)

Related

Linked list recursive delete operation: How do I change the head?

class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
def rec_delete(head, val, prev=None):
if(head == None):
return False
if(head.val == val):
if(prev == None):
head = head.next
else:
prev.next = head.next
return True
return rec_delete(head.next, val, head)
head = Node(1, Node(2, Node(3, Node(4))))
rec_delete(head, 1)
rec_delete(head, 2)
rec_delete(head, 3)
rec_delete(head, 4)
Given a linked list 1 -> 2 -> 3 -> 4 I want to remove all the elements one by one but unsure how to assign a new head in python. The issue with my current code is since head goes through a function I cannot reassign the head. I want head to be None after all the operations.
Your delete function needs to return the head of the list after val has been deleted. This not only makes the implementation of the delete much simpler (the base case is the one where the head is itself being deleted), it is necessary for the caller to be able to handle the case where the head is deleted.
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
def __repr__(self):
"""val1 -> val2 -> val3 ..."""
return f"{self.val}" + (f" -> {self.next}" if self.next else "")
def delete(head, val):
"""Delete val from list with given head, returning head of the modified list."""
if head.val == val:
# Deleting head, so the new head is head.next.
return head.next
# Head remains head, but we still need to delete val from head.next.
head.next = delete(head.next, val)
return head
head = Node(1, Node(2, Node(3, Node(4))))
print(head) # 1 -> 2 -> 3 -> 4
head = delete(head, 1)
head = delete(head, 2)
print(head) # 3 -> 4
head = delete(head, 3)
head = delete(head, 4)
print(head) # None

Iteratively/Recursively create a linked list

Need to recursively or iteratively create a linked list for a given number string.
For example:
Number = "123"
1 -> 2 -> 3
I wrote a recursive function but doesn't seem to work, it is creating a linked list but without the middle values. 1 -> 3 instead of 1 -> 2 -> 3
def create_linked_list(head, num):
if num is "":
return head
else:
head.next = ListNode(num[0])
return create_linked_list(head.next, num[1:])
n = "123"
head = ListNode(n[0])
result = create_linked_list(head, n[1:])
while result:
print(result.val)
head = result.next
# This is printing 1 -> 4
This is the original use case
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
n = "1234"
# I need this part of linked list creation to be done
# in a looping/recursive manner for any kind of number.
l1 = ListNode(n[0])
l1.next = ListNode(n[1])
l1.next.next = ListNode(n[2])
l1.next.next.next = ListNode(n[3])
while l1:
print(l1.val)
head = l1.next
# 1 -> 2 -> 3 -> 4
Your recursive approach looks correct. Only thing you need to do is. you don't need to return head when you reach end of number. Because you are already storing head in head variable.
Here is code that works.
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
n = "1234"
def create_linked_list(head, num):
if num is "": #base condition.
return
else:
head.next = ListNode(num[0])
create_linked_list(head.next, num[1:])
head = ListNode(n[0])
temp = head
create_linked_list(head, n[1:])
while temp:
print(temp.val)
temp = temp.next
Output
1
2
3
4
You can also rewrite above code as following.
def create_linked_list(head, num):
if num is not "":
head.next = ListNode(num[0])
create_linked_list(head.next, num[1:])
PS: Remember to always back up your head when working with Linked Lists.
Recursion is a functional heritage and so writing our program in functional style yields the best results. This means we avoid things like mutating the list nodes, head.next = .... Your constructor should be able to set both val and next -
class node:
def __init__(self, val, next = None):
self.val = val
self.next = next
def create_llist(v = None, *vals):
if not v:
return None
else:
return node(v, create_llist(*vals))
def llist_to_str(l = None):
if not l:
return "None"
else:
return f"{l.val} -> {llist_to_str(l.next)}"
print(llist_to_str(create_llist(1, 2, 3)))
# 1 -> 2 -> 3 -> None
But create_llist and llist_to_str would probably be more consistent if we implemented them as part of the class. And maybe a better name is llist, for "linked list" -
class llist:
def __init__(self, val, next = None):
self.val = val
self.next = next
def create(v = None, *more):
if not v:
return None
else:
return llist(v, llist.create(*more))
def __str__(self):
return f"{self.val} -> {self.next}"
print(llist.create(1, 2, 3))
# 1 -> 2 -> 3 -> None
Instead of relying on side effects, functions take inputs and produce an output. As a result, notice how we our mind is free of complexity -
class llist:
# ...
def map(node = None, f = lambda x: x):
if not node:
return None
else:
return llist(f(node.val), llist.map(node.next, f))
print(llist.map(llist.create(7, 8, 9), lambda x: x * x))
# 49 -> 64 -> 81 -> None

Singly linked list is not reversing when using recursion

I'm having trouble figuring out what's missing. I've taken a several looks at other solutions online, and those don't seem to work when I apply the differences. I've spent a good amount of time trying to debug. Here's my code:
def recurse_reverse(self, curr, level):
print('-' * level, 'curr:', curr.value, '| next:', curr.next.value if curr.next else curr.next)
if (not curr) or (not curr.next): # if there's 0 or 1 node
return curr
# p = self.recurse_reverse(curr.next, level + 1)
self.recurse_reverse(curr.next, level + 1)
print('-' * level, 'curr:', curr.value, '->', curr.next.value, '->',
curr.next.next.value if curr.next.next else curr.next.next)
curr.next.next = curr
# checking if pointer moved
print('-' * level, 'curr:', curr.value, '->', curr.next.value, '->',
curr.next.next.value if curr.next.next else curr.next.next)
# curr.next = None
# return p
The output I get when I call
my_list = SinglyLinkedList()
my_list.add_to_tail(1)
my_list.add_to_tail(2)
my_list.add_to_tail(3)
my_list.add_to_tail(4)
print(my_list._head.value) # 1
print(my_list._head.next.value) # 2
print(my_list._head.next.next.value) # 3
print(my_list._head.next.next.next.value) # 4
my_list.recurse_reverse(my_list._head, 1)
is this:
- curr: 1 | next: 2
-- curr: 2 | next: 3
--- curr: 3 | next: 4
---- curr: 4 | next: None
--- curr: 3 -> 4 -> None
--- curr: 3 -> 4 -> 3
-- curr: 2 -> 3 -> 4
-- curr: 2 -> 3 -> 2
- curr: 1 -> 2 -> 3
- curr: 1 -> 2 -> 1
So printing at each level, it seems that the pointers are being moved correctly. However when I try to print the linked list's head and tail I call recurse_reverse, I get 1 and 3, respectively; yet, what I would expect is 4 and 1.
In many solutions I've seen, the last line of the code is curr.next = None, to remove the next pointer of the current node, but when include that in my code, I get AttributeError: 'NoneType' object has no attribute 'value'
I've also tried setting
p = self.recurse_reverse(curr.next, level + 1)
and then return p on the last line, but that doesn't work either.
Here's my implementation:
class _LinkNode:
def __init__(self, value):
self.value = value
self.next = None
class SinglyLinkedList:
def __init__(self):
self._head = None
self._tail = None
self._length = 0
def add_to_tail(self, value):
"""
Add a new node to the tail of the linked list.
Parameters
----------
value : int, float, string, dict, list, etc.
"""
new_node = _LinkNode(value)
if self._head is None: # if linked list is empty
self._head = new_node
if self._tail: # if linked list has a tail, i.e. > 1 node
self._tail.next = new_node
self._tail = new_node # regardless of current length, update tail
self._length += 1
def recurse_reverse(self, curr, level):
# see above
There are two issues with your code. First if list contains more than one element you don't swap _head.next, after recurse_reverse it will still point to second element of the original list and thus the last two elements of reversed list form a loop.The second issue is what you don't swap _head and _tail anywhere in your code.
Here's one way to to implement the reversal recursively:
#staticmethod
def reverse(prev, node):
# Recurse until end of the list
if node:
SinglyLinkedList.reverse(node, node.next)
node.next = prev
def recurse_reverse(self):
# Reverse nodes
SinglyLinkedList.reverse(None, self._head)
# Swap head & tail since they are reversed now
self._head, self._tail = self._tail, self._head

Deleting node from a singly linked list (except for the tail)

I'm a beginner to programming and I'm trying to understand the following code:
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def deleteNode(self, node):
node.val = node.next.val
node.next = node.next.next
My intuition for the code is the following:
I understand that node is a reference to an element in the linked list and node.next is a pointer to the next node. I also understand that node.val sets the value of the current node to the value of the next node. What exactly is the purpose of
node.next = node.next.next?
Imagine the following linked list nodes (where n2 is the node you're removing)
... -> n1 -> n2 -> n3 -> ...
node -^ ^ ^- node.next.next
|
node.next
So if you set node.next = node.next.next you get this:
n2
|
v
... -> n1 -> n3 -> ...
node -^ ^
|
node.next
And since now nothing is referring to n2 once the function returns it will be garbage collected.
NodeA -> NodeB -> NodeC
So currently NodeA.next is NodeB
by assinging NodeA.next = NodeA.next.next we get NodeA.next = NodeB.next which makes
NodeA.next = NodeC
so the chain is now
NodeA -> NodeC
It means that the link to next node is removed and this node links to next.next node , it means the next node is deleted and its value replace with this node value.
for example we have following list:
1->2->3->4
1.next(2) = 1.next.next(3)
so list updatedt to:
1->3->4

How to find middle element of linked list in one pass in python?

I am trying to solve a linked list problem, to find the middle element in a single pass using python. Could someone please review my code and suggest the best manner to do this?
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
def print_nodes(node):
while node:
print node
node = node.next
def find_middle(node):
while node:
current = node
node = node.next
second_pointer = node.next
next_pointer = second_pointer.next
if next_pointer is None:
return "Middle node is %s" % str(current)
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
print find_middle(node1)
I merged all the methods for you creating, finding and printing.
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
def create_linked_list(n):
"""Creating linked list for the given
size"""
linked_list = Node(1)
head = linked_list
for i in range(2, n):
head.next = Node(i)
head = head.next
return linked_list
def print_linked_list(node):
"""To print the linked list in forward"""
while node:
print '[',node,']','[ref] ->',
node = node.next
print '-> None'
def find_middle1(node):
tick = False
half = node
while node:
node = node.next
if tick:
half = half.next
tick = not tick
return "Middle node is %s" % str(half)
def find_middle2(node):
list = []
while node:
list.append(node)
node = node.next
return "Middle node is %s" % str(list[len(list)/2])
node = create_linked_list(10)
print_linked_list(node)
print find_middle1(node)
print find_middle2(node)
Output:
[ 1 ] [ref] -> [ 2 ] [ref] -> [ 3 ] [ref] -> [ 4 ] [ref] -> [ 5 ] [ref] -> [ 6 ] [ref] -> [ 7 ] [ref] -> [ 8 ] [ref] -> [ 9 ] [ref] -> -> None
Middle node is 5
Middle node is 5
Here's on way, it's one pass, though probably not as efficient as you'd like:
def find_middle(node):
list = []
while node:
list.append(node)
node = node.next
return list[len(list)/2]
does that work?
You could keep two pointers, one that moves half as fast as the other.
def find_middle(node):
tick = False
half = node
while node:
node = node.next
if (tick):
half = half.next
tick = not tick
return "Middle node is %s" % str(half)
pseudo code for finding middle element of linked list : -
fast = head
slow = head
while(fast!=null) {
if(fast.next!=null) {
fast = fast.next.next
slow = slow.next
}
else {
break
}
}
// middle element
return slow
All of the above answers are right but for me, this worked best:
def middleNode(self, head: ListNode) -> ListNode:
list=[]
while head:
list.append(head)
head=head.next
return list[floor(len(list)/2)]
Here, using floor helped me otherwise my code gave me errors.
OK, this is NOT a good idea. But it DOES satisfy the constraint of traversing only once. Instead of traversing once (and a secondary half traversal), it (ab)uses the stack to emulate the half traversal (backwards instead of forwards). It's not a good idea, because Python doesn't have an infinitely growable stack (I wish Python would take a cue from the Smalltalk guys on this one), so you really can only handle lists in the size of hundreds, definitely not thousands (this is Python3, btw).
First I modified your script to build bigger lists with the change of a value:
last = root = Node(1)
for i in range(2, 312):
node = Node(i)
last.next = node
last = node
Since we're using the stack and recursion, we need a way to return abruptly out of a deep call stack. So we create an Exception subclass, which is really more of a "notification" than an "exception".
class FoundMiddleNode(Exception):
def __init__(self, node):
super().__init__()
self.node = node
Now for the recursive function:
def probeForMiddle(node, length):
if node.next is None: #recursion stopper
return length
#call recursively
lengthToEnd = probeForMiddle(node.next, length + 1)
#is my distance from start half of what is being returned recursively as the full length?
if (lengthToEnd // 2) - length == 0:
raise FoundMiddleNode(node) #throw an exception to abort the rest of the stack walk
return lengthToEnd
And to use it we do:
try:
probeForMiddle(root, 0)
except FoundMiddleNode as e:
print(e.node)
Not pretty. Not a good idea in anything approximating production code. But a decent example of (ab)using recursion and exceptions to fill the requirement of only traversing once.
The best way to find the middle node is to have two pointers:
P1 = root
P2 = root
While not p2.next == Null:
P1 =p1.next
P2 =P2.next.next
//Linked list
ll = {'A': ["data", "B"],
'B': ["data", "C"],
'C': ["data", "D"],
'D': ["data", "E"],
'E': ["data", None]}
def find_next_node(node="A"):
return ll[node][1] if ll[node][1] else None
def find_mid_node(head="A"):
slow = head
fast = head
while(fast!=None):
for i in range(2):
if find_next_node(fast):
fast = find_next_node(node=fast)
else:
return slow
for j in range(1):
slow = find_next_node(node=slow)
print (find_mid_node())
You can write a smaller code for finding the middle node. Showing the snippet below:
def find_middle(node):
half = node
while node and node.next is not None:
node = node.next.next
half = half.next
return half
Few important points:
Logic will remain the same of keeping two pointers, one fast and other slow.
Write a Linked list class to create a linked list with the help of loop rather than explicitly setting next pointers.
This is very similar to what James and Jordan have posted already, it's just little simpler in terms of what it does and I've added explanation as comments to what's actually doing
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
# loop through the items and check for next items using two pointers (fast and slow)
# set the speed for fast twice higher than the slow pointer so when when fast reaches
# the end the slow would be in the middle
def find_middle(head ):
fast = slow = head
#slow = head
while fast.next != None and fast.next.next != None:
fast = fast.next.next
slow = slow.next
# slow is now at the middle :)
print (slow.data )
#setup data
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
find_middle(node1)
I might be little late but this works best for me. Writing complete code for creating, finding the midpoint & printing the linked list.
class Node:
'''
Class to create Node and next part of the linked list
'''
def __init__(self,data):
self.data = data
self.next = None
def createLL(arr):
'''
linked list creation
'''
head = Node(arr[0])
tail = head
for data in arr[1:]:
tail.next = Node(data)
tail = tail.next
return head
def midPointOfLL(head):
'''
Here, i am using two pointers slow and fast, So idea is fast will be 2 times faster than slow pointer
and when fast reaches the end of the linked list slow pointer will be exactly in the middle.
'''
slow = head
fast = head
if head is not None:
while (fast.next is not None) and (fast.next.next is not None):
slow = slow.next
fast = fast.next.next
return slow
def printLL(head):
curr = head
while curr :
print(curr.data,end = "-->")
curr = curr.next
print('None')
arr = list(map(int,input().split()))
head = createLL(arr)
midPoint = midPointOfLL(head)
print(midPoint.data)
printLL(head)
list=['ok','go','no','poi','duo','ok','go','nah']
b=0
b=int(len(list)/2) #print the middle element change .5 values
print(list[b])
if((len(list)%2)==0): #if list is of even number print both middle values
print(list[b+1])
when i searched this question i was looking for something like this so i can get both middle values when entered even num of elements
there must be a better way to do it i just start coding from like 3,4 day

Categories