I have a linked-list and I want to calculate it's length with a function, here's my definition :
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
Try this function:
def length(lst):
r = 0
while lst:
lst = lst.next
r += 1
return r # 'r' being the length
It works by moving forward along the list counting the number of nodes observed until a None link is encountered.
You can simply set the head node to a variable, and continuous count until you hit the point where temp == NULL
def height(list):
temp=list.head
count=0
while temp:
count+=1
temp=temp.next
return count
Related
I am creating the Josephus problem using a circular doubly linked list. I am getting an Attribute error, which I assume is because my current_node (first node) does not have a .prev yet.
I understand that the prev of my first node should point to the next of my last node to create a circular doubly linked list.
Can someone guide me on whether I have correctly identified the error? If yes, how can I rectify it?
If not, then what are the other ways I can correct the error?
#Initialize the node
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
def remove(self, n):
print("Student " +str(n)+ " was removed")
class Circle:
# Initializing the DLL
def __init__(self):
self.head = None
self.tail = None
#Inserting elements 2 to n in the dll
def insert_after(self, x, data):
y = Student(data) # make a new Node object.
z = Student(data)
z = x.next
y.prev = x
y.next = z
x.next = y
z.prev = y
def josephus_solution(self, dllist, n, k):
no_of_active_nodes = n
current_node = Student(1)
#last_node = Student(n)
#print(current_node.prev)
for i in range(2, n + 1):
dllist.insert_after(current_node, i)
count = 0
#print(current_node.data)
while (current_node.next != current_node.prev):
#print(current_node.next.prev)
current_node = current_node.next
count += 1
#print(current_node.data)
if (count == k):
current_node.remove(current_node.data)
current_node.prev.next = current_node.next
current_node.next.prev = current_node.prev
count = 0
no_of_active_nodes -= 1
#print(no_of_active_nodes)
if (no_of_active_nodes == 1):
print("Student" + str(current_node.data) + "Recieves the scholarship")
return current_node.data
dllist = Circle()
n = 5 #int(input('Input number of people (n): '))
k = 2 #int(input('The nth person will be executed. Input k: '))
ans = dllist.josephus_solution(dllist, n, k)
Error
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/tmp/ipykernel_24/3762059582.py in <module>
54 n = 5 #int(input('Input number of people (n): '))
55 k = 2 #int(input('The nth person will be executed. Input k: '))
---> 56 ans = dllist.josephus_solution(dllist, n, k)
/tmp/ipykernel_24/3762059582.py in josephus_solution(self, dllist, n, k)
32 #print(current_node.prev)
33 for i in range(2, n + 1):
---> 34 dllist.insert_after(current_node, i)
35 count = 0
36 #print(current_node.data)
/tmp/ipykernel_24/3762059582.py in insert_after(self, x, data)
24 x.next = y
25
---> 26 z.prev = y
27
28 def josephus_solution(self, dllist, n, k):
AttributeError: 'NoneType' object has no attribute 'prev'
The direct reason for the error is that z is None and your code can therefore not access any prev attribute of it in the line z.prev = y. The cause is that when the first node is created, its prev and next attributes are initialised to None, and when this node is passed as x argument to insert_after, then with z = x.next a None value is assigned to z.
There are several issues with your approach:
In insert_after it makes no sense to call Student twice, since you want to insert one node, not two
Although your Circle class has a head and a tail attribute, they are never used after their initialisation to None, so there is actually nothing in the Circle instance that helps you to maintain the list. You might as well define all methods on the Student class.
The while condition in josephus_solution is probably intended to test that only one node remains in the list, but it actually verifies whether there are two left. Admittedly, this works when current_node is a node that was just deleted, but then the returned data is the data of the deleted node and not the remaining active node, and current_node is not a just-deleted node, then this condition will make the loop exit when it still has two active nodes.
Some other remarks:
As you call josephus_solution as a method, it should not be necessary to also pass an instance as argument. self is already available to that method
I would split the creation of the nodes into a separate -- generic -- method, and let josephus_solution work on an existing linked list.
As in a circular list none of the next or prev attributes should ever be None, you'll make things easier when initialising them to self instead of None.
The remove method should not be responsible for printing a message, but should on the other hand be responsible for rewiring the prev and next references. At any rate, there is no need for this method to get an argument, as it knows its own attributes through self.
In the original Josephus problem, the first node is numbered as 1, so with k=2 the first node to remove is the one with number 2. Your code would first delete the one with number 3. To align with the original problem, move the current_node = current_node.next statement to be the last line in the body of the loop. This also helps to be sure that current_node is never a just-deleted node when the while condition is evaluated.
As your while condition already takes care of when to stop, there should be no reason to keep track with a no_of_active_nodes variable.
There are more remarks to make, but these are what I believe the most important.
Here is a correction of your code, taking all of the above into account:
class Student:
def __init__(self, data):
self.data = data
# Better make prev/next self references to avoid None:
self.next = self
self.prev = self
def remove(self):
# Perform the remove here
self.prev.next = self.next
self.next.prev = self.prev
def insert(self, data):
# Should only create one node, not two
node = Student(data)
node.next = self
node.prev = self.prev
self.prev = node.prev.next = node
# Handy method to create a circular list from values
#classmethod
def fromiterator(cls, iterator):
head = cls(next(iterator))
for value in iterator:
head.insert(value)
return head
def josephus_solution(self, k):
count = 0
current_node = self
while current_node.next is not current_node: # This is how to test for 1 node
count += 1
if count == k:
current_node.remove() # No argument
print("Student " +str(current_node.data) + " was removed")
count = 0
current_node = current_node.next # do this at the end of the iteration
# No need to keep track of active nodes ...
return current_node
# These are the parameters of the "original" problem (see Wikipedia)
n = 41
k = 3
dllist = Student.fromiterator(iter(range(1, n+1)))
# Don't pass the list as argument: it already is available as `self`
dllist = dllist.josephus_solution(k)
# Perform output in the main code, not inside method
print("Student " + str(dllist.data) + " recieves the scholarship")
I am working on this challenge:
Sort a Linked list in increasing order by considering two nodes as a two digit number. (in place sorting)
4 ≤ n ≤ 1000
The length of the linked list is always even.
Example 1:
Input
1→3→4→2→1→2
Output
1→2→1→3→4→2
Explanation:
12 > 13 > 42
Example 2:
Input
1→3→0→3
Output
0→3→1→3
Here is my linked list template implementation; which anyone can start coding:
class Node():
def __init__(self,val):
self.data = val
self.next = None
class Linkedlist():
def __init__(self):
self.head = None
def add(self,x):
t = Node(x)
t.next = self.head
self.head = t
def display(self):
p = self.head
while p != None:
print(p.data)
p=p.next
def sort(self):
curr = self.head
# your logic here
m = Linkedlist()
m.add(1)
m.add(3)
m.add(4)
m.add(2)
m.add(1)
m.add(2)
m.display()
Which is the algorithm to sort the pairs in a linked list (in place), and how can I code it?
First write a function that accepts a linked list of single digit nodes and merges each pair of adjacent single digit nodes into a linked list of half as many nodes, where each node contains a double digit number.
Then sort the resulting linked list using bubble sort, which is O(n^2), or mergesort, which is O(nlogn).
Then, if need be, write a third function that takes apart the double digit nodes and creates a new list of twice as many single digit nodes.
Doing it with two or three functions like this will really simplify the sort.
First of all, your current code will not generate list 1→3→4→2→1→2, but its inverse. This is because your definition of the add method will prepend the given value to the list.
To make add work correctly, it should first find the last node in the list, and append the new node after it. As this is not a very efficient method to add many values to a list, I would suggest to also define add as a Node method, and to allow chaining add calls. That way you can add many values in one chained expression without being inefficient.
Also, as you will need to compare values of pairs, it makes sense to make a method on Node that will return the value of the pair formed by that node and the next in the list.
Finally, for the sort algorithm itself, you could reduce the list to its first pair only (which is then obviously sorted), and treat the rest as a separate list of unsorted nodes. Then extract a pair at a time from the unsorted list, and find the right place to inject it in the main list, so that it remains sorted.
This process represents O(n²) time complexity on average and in the worst case. The best case is O(n), which occurs when the list is originally sorted in reverse order.
Here is how that could look:
class Node():
def __init__(self, val):
self.data = val
self.next = None
# Easy chaining: defining this method on a Node as well
def add(self, val):
node = Node(val)
node.next = self.next
self.next = node
return node
# Define how the value of a pair is calculated
def pairvalue(self):
return self.data * 10 + self.next.data
class Linkedlist():
def __init__(self):
self.head = None
def add(self, val):
# Corrected method: addition should be at the end of the list
node = Node(val)
if not self.head:
self.head = node
else: # Look for the last node in the list
curr = self.head
while curr.next:
curr = curr.next
# ...and append the new node after it
curr.next = node
return node # Allow for chaining
def display(self):
p = self.head
while p:
print(p.data, end= "→")
p = p.next
print("NIL")
def sort(self):
if not self.head:
return
# Reduce list to just its first pair
# The remainder is a temporary "todo" list
todo = self.head.next.next
self.head.next.next = None
while todo:
pair = todo # The pair that will be added to the sorted list
todo = todo.next.next
val = pair.pairvalue()
if val < self.head.pairvalue():
# The pair is a minimum: prepend it
pair.next.next = self.head
self.head = pair
else:
curr = self.head.next # odd index
# Find insertion point in sorted list
while curr.next and curr.next.pairvalue() < val:
curr = curr.next.next
# Perform insertion
pair.next.next = curr.next
curr.next = pair
m = Linkedlist()
m.add(1).add(3).add(4).add(2).add(1).add(2)
m.display() # original list
m.sort()
m.display() # final list
The output:
1→3→4→2→1→2→NIL
1→2→1→3→4→2→NIL
I have defined a class to make a linked list as follows:
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
Now, I've generated a number "sum" and wrote the following code to generate the Linked List: (assuming that sum could possibly have 3 or 4 digits)
if len(str(sum)) == 4:
l3 = ListNode(str(sum)[3])
l3.next = ListNode(str(sum)[2])
l3.next.next = ListNode(str(sum)[1])
l3.next.next.next = ListNode(str(sum)[0])
elif len(str(sum)) == 3:
l3 = ListNode(str(sum)[2])
l3.next = ListNode(str(sum)[1])
l3.next.next = ListNode(str(sum)[0])
Is there a way to generate the above using the length of the number "sum" without hard-coding as above?
you could do something like this:
s = str(975)
start_node = node = ListNode(s[-1]) # initialize to last character in s
for c in reversed(s[:-1]):
node.next = ListNode(c)
node = node.next
start_node should now contain the first node; from there you could .next to the next node. node always points to the current node in the loop (and could be discarded after the loop).
note that sum is a built-in function and therefore not a good variable name...
the output of the code above:
print(start_node.val) # 5
print(start_node.next.val) # 7
print(start_node.next.next.val) # 9
print(start_node.next.next.next) # None
you could even write the code above more compact (but way less readable imo):
start_node = node = ListNode(s[-1])
for c in reversed(s[:-1]):
node.next = node = ListNode(c)
class SortedList:
theList = []
def add(self, number):
self.theList.append(number)
return self.theList
def remove(self, number):
self.theList.remove(number)
return self.theList
def printList(self):
return print(self.theList)
def binarSearch(self, number):
middle = (len(self.theList)//2)
end = len(self.theList)
if end != 0:
if int(self.theList[middle]) == int(number):
return print("The number is found in the list at place",middle+1)
elif int(self.theList[middle]) < int(number):
self.theList = self.theList[middle:]
return self.binarSearch(number)
elif int(self.theList[middle]) > int(number):
self.theList = self.theList[:middle]
return self.binarSearch(number)
else:
return print("The list is empty")
sorted = SortedList() #create a SortedList object
sorted.add("1")
sorted.add("2")
sorted.add("3")
sorted.add("4")
sorted.add("5")
sorted.add("6")
sorted.printList()
sorted.binarSearch(3)
I cannot use additional parameters I mut use only self and number. I want to make it recursive but if it is hard you can answer as normal.
This code works good until the number 4. When I give 4 for searching it says it is in place 2 and it continues saying two after 4. I have tried adding other numbers but it is same
Python already has a great module bisect which performs a binary search for sorted lists:
import bisect
l = [2,3,1,5,6,7,9,8,4]
print(bisect.bisect(l, 4)) # Output: 3
Familiarize yourself with this library:
https://docs.python.org/3.5/library/bisect.html
Just a hint: You can use additional parameters if you give them default values. Your method signature would look like this:
def binarSearch(self, number, start=0, end=len(self.theList)):
So it could still be called like sorted.binarySearch(5) but would internally be able to pass the state correctly.
I want to have a number that breaks into 2 other numbers and checks for end conditions, breaking off each number until the conditions are met.
I came up with the following example to try to figure it out. Take a number, and break it into 2 more numbers: one is the original number multiplied by 2 and the other number is the original number divided by 3 without a remainder (//). This continues until a number is either greater than 100, equal to 6, or a square.
I want to record every chain that is made to be returned and printed out at the end. I can only do this by checking the second number in a chain currently and am not clever enough to figure out how to check both numbers. I want a new chain to be created every time the number is broken into 2 new numbers.
Currently, here is what I have:
import numpy as np
def check_conditions(number):
if number > 100:
return False
if number == 6:
return False
if np.sqrt(number) % 1 == 0:
return False
return True
def find_decay(number):
'''
Rule: Number is broken into two chains. First chain is
mulitplied by 2. Seconds chain is // 3. Same thing happens
to both chains unless end condition is met:
1. number is greater than 100
2. number is equal to 6
3. number is a perfect square
'''
master_chain = []
while check_conditions(number):
new_chain1 = [number * 2]
master_chain.append(new_chain1)
new_chain2 = [number // 3]
master_chain.append(new_chain2)
number = new_chain2[-1]
return master_chain
if __name__ == '__main__':
print find_decay(int(raw_input('Number: ')))
Does anyone have any ideas of ways to check conditions in a while loop for 2 separate numbers like?
This sort of problem typically lends itself to trees and/or recursion. However, the rate at which you're spawning new work is quite high compared to the rate at which you're going to satisfy the conditions. (ie while it won't take too many operations to exceed 100 for one product of each value, but low chances of finding a perfect square or exactly 6 on either fork)
Therefore, you'll want to set a max recursion depth for your implementation else you'll come up against the interpreter's limit (sys.getrecursionlimit()) and fail ugly.
I've provided a simple example of how you might do it below, recursively building a tree.
This is not particularly efficient though, and if you are interested in very long 'chains' then you may need to consider addressing this another way.
import sys
import numpy as np
class Node(object):
def __init__(self,number,parent):
self._parent = parent
self._number = number
self._satisfied = number > 100 or number == 6 or np.sqrt(number) % 1 == 0
self._left = None
self._right = None
self._depth = parent.depth + 1 if parent != None else 1
#property
def parent(self):
return self._parent
#property
def number(self):
return self._number
#property
def satisfied(self):
return self._satisfied
#property
def depth(self):
return self._depth
#property
def left(self):
return self._left
#left.setter
def left(self,value):
self._left = value
#property
def right(self):
return self._right
#right.setter
def right(self,value):
self._right = value
def print_all_chains(node,chain=[]):
if node.left is None:
chain.append(node.number)
print '{0}: {1}'.format(node.satisfied, chain)
else:
print_all_chains(node.left, chain[:] + [node.number])
print_all_chains(node.right, chain[:] + [node.number])
def build_tree(node, maxDepth):
if not node.satisfied and node.depth<maxDepth:
node.left = Node(node.number*2, node)
build_tree(node.left,maxDepth)
node.right = Node(node.number//3, node)
build_tree(node.right,maxDepth)
def find_decay(number):
root = Node(number,None)
build_tree(root,maxDepth=10)
print_all_chains(root)
if __name__ == '__main__':
find_decay(int(raw_input('Number: ')))
Using a simple Node class, this can give you an idea of the tree structure. This traverses the tree in level-order (which guarantees to find the shortest chain):
from collections import deque
import numpy as np
def check_conditions(number):
return number > 100 or number == 6 or np.sqrt(number) % 1 == 0
class Node():
def __init__(self, value, parent=None):
self.value, self.parent = value, parent
def chain(self):
node = self
while node:
yield node.value
node = node.parent
def find_decay(number):
agenda = deque([Node(number)])
while agenda:
node = agenda.popleft() # use pop() for depth-first
num = node.value
if check_conditions(num):
return list(node.chain())
agenda.append(Node(num//3, parent=node))
agenda.append(Node(num*2, parent=node))
if __name__ == '__main__':
for x in find_decay(int(raw_input('Number: '))):
print x,
37: 37 12 4