def filter(f, lst):
if lst == []: return []
if f(lst[0]): return [lst[0]] + filter(f, lst[1:])
return filter(f, lst[1:])
def my_reverse(lst): # Reverse the list
def reverse_helper(x,y):
if x == []: return y
return reverse_helper(x[1:], [x[0]] + y)
return reverse_helper(lst, [])
def revfilter_alpha(f, lst): # Reverse and filter ...
return my_reverse(filter(f, lst))
def revfilter_beta(f, lst): # Reverse and filter ...
if lst == []: return []
return revfilter_beta(f, lst[1:]) + ([lst[0]] if f(lst[0]) else [])
Could someone explain to me how to determine the running time in Big Θ notation for these? I’ve read quite a few things but still have no idea where to begin.
In filter, I think it is Θ(n^2) because it checks each element in list of size n with the predicate function f with n recursive calls so n*n.
revfilter_beta looks pretty similar just reversing while filtering so wouldn’t this also be Θ(n^2)?
revfilter_alpha does filter then a reverse, so wouldn’t this be n^2*n^2 = Θ(n^4)?
Does anyone have any thoughts?
filterhasnrecursive calls, but you also do a copy operation on each iteration which takesn, so you end up having Θ(n^2). If you implemented it ‘properly’ it should be Θ(n) though.Same for
my_reverse.Same for
revfilter_beta.revfilter_alphajust does afilterand then areverse, so thats Θ(n^2 + n^2) = Θ(n^2).EDIT: Let’s look into
filtera bit more.What you want to figure out is how many operations are performed relative to the size of the input.
O(n)means that at the very worst case, you will do on the order ofnoperations. I say “on the order of” because you could, for example, doO(n/2)operations, orO(4n), but the most important factor isn. That is, asngrows, the constant factor becomes less and less important, so we only look at the non-constant factor (nin this case).So, how many operations does
filterperform on a list of sizen?Let’s take it from the bottom up. What if
nis 0 – an empty list? Then it will just return an empty list. So let’s say that’s 1 operation.What if
nis 1? It will check whetherlst[0]should be included – that check takes however long it takes to callf– and then it will copy the rest of the list, and do a recursive call on that copy, which in this case is an empty list. sofilter(1)takesf + copy(0) + filter(0)operations, wherecopy(n)is how long it takes to copy a list, andfis how long it takes to check whether an element should be included, assuming it takes the same amount of time for each element.What about
filter(2)? It will do 1 check, then copy the rest of list and callfilteron the remainder:f + copy(1) + filter(1).You can see the pattern already.
filter(n)takes1 + copy(n-1) + filter(n-1).Now,
copy(n)is justn– it takesnoperations to slice the list in that way. So we can simplify further:filter(n) = f + n-1 + filter(n-1).Now you can try just expanding out
filter(n-1)a few times to see what happens:Can we generalize for
xrepetitions? That1, 3, 6, 10, 15… sequence is the triangle numbers – that is,1,1+2,1+2+3,1+2+3+4, etc. The sum of all numbers from1toxisx*(x-1)/2.Now, what is
x? How many repetitions will we have? Well, you can see that whenx=n, you have no more recursion –filter(n-n)=filter(0)=1. So our formula is now:Which we can simplify further:
So there ya have it – a rather detailed analysis. That would be
Θ((1/2)n^2 + (f + 1/2)n + 1)… assumingfis insignificant (sayf=1) that gets toΘ((1/2)n^2 + (3/2)n + 1).Now you’ll notice, if
copy(n)took a constant amount of time instead of a linear amount of time (ifcopy(n)was 1 instead ofn), then you wouldn’t get thatn^2term in there.I’ll admit, when I said
Θ(n^2)initially, I didn’t do this all in my head. Rather, I figured: ok, you havenrecursive steps, and each step will takenamount of time because of thecopy.n*n = n^2, thusΘ(n^2). To do that a bit more exactly,nshrinks at each step, so you really haven + (n-1) + (n-2) + (n-3) + ... + 1, which ends up being that same figure as above:n*n - (1 + 2 + 3 + ... + n)=n*n - n*(n-1)/2=(1/2)n^2 + (1/2)n, which is the same if I had used0instead off, above. Likewise, if you hadnsteps but each step took1instead ofn(if you didn’t have to copy the list), then you’d have1 + 1 + 1 + ... + 1,ntimes, or simplyn.But, that requires a bit more intuition so I figured I’d also show you the brute force method that you can apply to anything.