Time complexity of binary search tree get_size method which i edited - recursion

I am struggling to find time complexity of get_size method which i created in Binary Search Tree because of the fact that there is multiple recursion with multiple conditions.Here is code
`class Node:
def __init__(self, data, left=None, right=None):
self.data = data
self.right = right
self.left = left
def __str__(self):
return str(self.data)
i created node class to stock data and then i created BST functions and it does work but problem is every functions time complexity should be log n in functions but i used if elif else and double recursion at the same time does it affect the run time if it does why if it doesn't why
class BST:
def __init__(self):
self.root = None
def add(self, value, x=None):
new_node = Node(value)
if self.root is None:
self.root = new_node
return True
if x is None:
main_node = self.root
else:
main_node = x
if value > main_node.data:
if main_node.left is None:
main_node.left = new_node
return True
else:
return self.add(value, main_node.left)
elif value == main_node.data:
return False
elif value < main_node.data:
if main_node.right is None:
main_node.right = new_node
return True
else:
return self.add(value, main_node.right)
def get_size(self, x=None):
if self.root is None:
return 0
if x is None:
main_node = self.root
else:
main_node = x
if main_node.left is not None and main_node.right is not None:
return 1 + self.get_size(main_node.left) + self.get_size(main_node.right)
elif main_node.left is None and main_node.right is None:
return 1
else:
if main_node.left is not None:
return 1 + self.get_size(main_node.left)
else:
return 1 + self.get_size(main_node.right)`

To determine the complexity, it helps to break your function apart and analyze the different parts separately.
Starting with the base cases, your complexity is O(1).
if self.root is None:
return 0
elif main_node.left is None and main_node.right is None:
return 1
However, as your start recursing, those base cases will add up. Let's look at one of the recursive calls:
if main_node.left is not None and main_node.right is not None:
return 1 + self.get_size(main_node.left) + self.get_size(main_node.right)
In the simplest tree where main_node's left and right children are both leaves, then these 2 calls to get_size() will not recurse any farther, resulting in two O(1) operations. However, if either of the nodes have children, then we will make additional calls to get_size(), making get_size() something greater than O(1). If the left child had children, but those children are leaves, then we will again call get_size() two more times, each being an O(1) call.
If we repeat this analysis for every possible if/else statement in the function, we will see that for each child that exists, we will call get_size() for it once and only once. Therefore, our overall complexity is O(n).

Related

Save descendence in family tree with a recursive function in Python

I have a dictionary of a family tree with the name of the child as the key and their dad's and mom's name in a list as the value.
d = {
'Kevin': ('Tom', 'Marge'),
'Marge': ('John', 'Mary'),
'Elle': ('Tom', 'Marge'),
'Seth': ('Tom', 'Marge'),
'Mary': ('Carl', 'Elena'),
'Tom': ('Joseph', 'Alice'),
'Alice': ('Rob', 'Amy'),
'John': ('James', 'Elena'),
'Joseph': ('Adam', 'Emma'),
'James': ('Nick', 'Maria') }
I need to write a recursive function so that it returns True when there is a descendence between two people. If there is a descendance, it has to print out the chain of relations, i.e:
>>> print("Is there a lineage?", lineage('Amy', 'Kevin', d))
Amy
Alice
Tom
Kevin
Is there a lineage? True
Otherwise if there isn't one:
>>> print("Is there a lineage?", lineage('Mary', 'Alice', d))
Is there a lineage? False
This is what I've got so far. It seems to return True or False consistantly, but I'm having troubles figuring out how to save the path between the two people.
line = []
def lineage(parent, child, d):
dad, mom = d[child][0], d[child][1]
try:
if parent in d[child]:
line.append(parent)
else:
try:
lineage(parent, dad, d)
except:
lineage(parent, mom, d)
return True
except:
return False
I'm new to recursion, so any ideas or help on how to approach this are much appreciated.
I made your function return the path, instead of True, when a path exists.
I recommend avoiding try / except here.
It is true that trying to access d[child] without checking that child is in d might result in an Exception. However, this is the base-case of your recursion; your code will be easier to understand if the base case is clearly identified with an explicit if at the beginning of your function, rather than with an obscure "some Exception happened" with no explanation at the end of your function.
def lineage(parent, child, d):
if parent == child:
return [child]
elif child not in d:
return False
else:
dad, mom = d[child][0], d[child][1]
path_via_dad = lineage(parent, dad, d)
if path_via_dad:
path_via_dad.append(child)
return path_via_dad
else:
path_via_mom = lineage(parent, mom, d)
if path_via_mom:
path_via_mom.append(child)
return path_via_mom
else:
return False
Here is a shorter, equivalent version, relying on the specific behaviour of logical operator or in python:
def lineage(parent, child, d):
if parent == child:
return [child]
elif child not in d:
return False
else:
dad, mom = d[child][0], d[child][1]
path = lineage(parent, dad, d) or lineage(parent, mom, d)
if path:
path.append(child)
return path
Testing:
>>> lineage('Amy', 'Kevin', d)
['Amy', 'Alice', 'Tom', 'Kevin']
>>> lineage('Mary', 'Alice', d)
False

AtrributeError MomentSGD optimizer has no attribute prepare

Recently, I run the code released by other authors. They utilized chainer v1.3, but I installed v4. When I run the code, it errors that Attribute Errors: MomentSGD optimizer has no attribute prepare. Here I post the codes of this part:
class BaseModel(chainer.Chain):
loss = None
accuracy = None
gpu_mode = False
_train = False
def __call__(self, *arg_list, **arg_dict):
raise NotImplementedError()
def clear(self):
self.loss = None
self.accuracy = None
def train(self, data, optimizer):
self._train = True
optimizer.update(self, data)
if self.accuracy is None:
return float(self.loss.data)
else:
return float(self.loss.data), float(self.accuracy.data)
def validate(self, data):
self._train = False
self(data)
if self.accuracy is None:
return float(self.loss.data)
else:
return float(self.loss.data), float(self.accuracy.data)
def test(self, data):
self._train = False
raise NotImplementedError()
def save(self, fname):
serializers.save_hdf5(fname, self)
def load(self, fname):
serializers.load_hdf5(fname, self)
def cache(self):
self.to_cpu()
cached_model = self.copy()
self.to_gpu()
return cached_model
# this part is the error part
def setup(self, optimizer):
self.to_gpu()
optimizer.target = self
optimizer.prepare()
def to_cpu(self):
if not self.gpu_mode:
return
super(BaseModel, self).to_cpu()
self.gpu_mode = False
def to_gpu(self):
if self.gpu_mode:
return
super(BaseModel, self).to_gpu()
self.gpu_mode = True
Newer version of chainer uses setup method to initialize optimizer.
Can you try modifing your code as follows?
def setup(self, optimizer):
self.to_gpu()
optimizer.setup(self)

how to compute a%b recursively?

I need to write a recursive function that returns the remainder of two numbers. Here's what I wrote:
def remainder(a,b):
if a==b:
return 0
else:
k=a-b
return a-b + remainder(b,a-k)
If we test remainder(5,3) the function will return 2 and it's correct but if we test remainder(15,3),
we'll get 12 and its false. I just don't know how to debug it.
You are missing a case: (when a < b)
def remainder(a,b):
if a<b: #trivial: remainder = a - b*0 = a
return a
else: #reduce the problem to a simple one
return remainder(a-b, b)
Test:
print remainder(15,3)
Output:
0
Here if you are lazy and don't want to write more than 2 lines:
def remainder(a,b):
return a if a < b else remainder(a-b, b)
It should be something like this :
def remainder(a,b):
if a<b:
return a
else:
return remainder(a-b,b)
You can do:
def remainder(a, b):
if a < b:
return a
return remainder(a - b, b)
Examples:
>>> remainder(15, 3)
0
>>> remainder(14, 3)
2
>>> remainder(13, 3)
1
If a < b then it means we're done: we know the result of the computation and we can return a. Otherwise we need to subtract b from a and we call remainder again recursively. This can then repeatedly continue until a is smaller than b. Once that happens the recursion stops (i.e., it won't call remainder again) but we're able to return the result.

Print within Recursion function Python3

the point of my recursion function is to print integers in reverse order.
def rDisp(s):
n=str(s)
if n == "":
return n
else:
return rDisp(n[1:]) + n[0]
def main():
number=(int(input("Enter a number :")))
rDisp(num)
main()
If within the main function I implement print(reverseDisplay(number)), it works, however, for the purpose of this code, I want the reverseDisplay function to do the printing. How would I go about implementing the print function into that block of code.
Thanks!
Untested code:
def reversePrint(s):
if not s:
return
print(s[-1])
reversePrint(s[:-1])
def main():
number=input("Enter a number :")
reversePrint(number)
main()
Just got it
def reverseDisplay(s):
n=str(s)
if n == "":
return n
else:
reverseDisplay(n[1:])
b=n[0]
print(b,end='')

How to call a closure with multiple parameters from collect() method of a groovy collection?

Let's say I have a closure:
def increment = {value, step ->
value + step
}
Now I want to loop over every item of my integers collection, increment it with 5, and save new elements to a new collection:
def numbers = [1..10]
def biggerNumbers = numbers.collect {
it + 5
}
And now I want to achieve the same result but by means of using increment closure. How can I do this?
Should be something like this (wrong code below):
def biggerNumbers = numbers.collect increment(it, 5) //what's the correct name of 'it'??
The solution to your problem would be nesting your call of increment in a closure:
def biggerNumbers = numbers.collect {increment(it, 5)}
If you wanted to pass a premade closure to the collect you should have made it compatible with collect - accepting a single parameter that is:
def incrementByFive = {it + 5}
def biggerNumbers = numbers.collect incrementByFive
mojojojo has the right answer, but just thought I'd add that this looks like a good candidate for currying (specifically using rcurry)
If you have:
def increment = {value, step ->
value + step
}
You can then curry the right-hand parameter of this function with:
def incrementByFive = increment.rcurry 5
And then, you can do:
def numbers = 1..10
def biggerNumbers = numbers.collect incrementByFive
Just thought it might be of interest ;-)
The main issue is that [1..10] creates a List<IntRange> which you are trying to increment. You should collect on the IntRange directly (note the lack of brackets):
(1..10).collect { it + 5 }
Or with curry:
def sum = { a, b -> a + b }
(1..10).collect(sum.curry(5))

Resources