Calculating big O swaps, calculations, and comparisons - algorithm

Looking at the code below:
Algorithm sort
Declare A(1 to n)
n = length(A)
for i = 1 to n
for j = 1 to n-1 inclusive do
if A[i-1] > A[i] then
swap( A[i-1], A[i] )
end if
next j
next i
I would say that there are:
2 loops, both n, n*n = n^2 (n-1 truncated to n)
1 comparison, in the j loop, that will execute n^2 times
A swap that will execute n^2 times
There are also 2n additions with the loops, executing n^2 times, so 2n^2
The answers given in a mark scheme:
Evaluation of algorithm
Comparisons
The only comparison appears in the j loop.
Since this loop will iterate a total of n^2
times, it will execute
exactly n^2
Data swaps
There may be a swap operation carried out in the j loop.
Swap( A[i-1], A[i] ) Each of these will happen n^2 times.
Therefore there are 2n^2 operation carried out within the j loop
The i loop has one addition operation incrementing i which happens n
times
Adding these up we the number of addition operations which is 2n^2 +
n
As n gets very big then n^2 will dominate therefore it is O(n^2)
NOTE: Calculations might include assignment operations but these will not affect overall time so ignore
Marking overview:
1 mark for identifying i loop will execute n times.
1 mark for identifying j loop will execute 2n^2 times Isn't this meant to be n*n = n^2? For i and j
1 mark for correct number of calculations 2n^2 + n Why is this not
+2n?
1 mark for determining that the order will be dominated by n^2 as n
gets very big giving O(n^2) for the algorithm
Edit: As can be seen from the mark scheme, I am expected to count:
Loop numbers, but n-1 can be truncated to n
Comparisons e.g. if statements
Data swaps (counted as one statement, i.e. arr[i] = arr[i+1], temp = arr[i], etc. are considered one swap)
Calculations
Space - just n for array, etc.
Could someone kindly explain how these answers are derived?
Thank you!

Here's my take on the marking scheme, explicitly marking the operations they're counting. It seems they're counting assignments (but conveniently forgetting that it takes 2 or 3 assignments to do a swap). That explains why they count increment but not the [i-1] indexing.
Counting swaps
i loop runs n times
j loop runs n-1 times (~n^2-n)
swap (happens n^2 times) n^2
Counting additions (+=)
i loop runs n times
j loop runs n-1 times (~n^2)
increment j (happens n^2 times) n^2
increment i (happens n times) n
sum: 2n^2 + n

Related

Finding the Big O of psuedocode

Here's the code:
y = 0
for j=0 to n:
for k=0 to (j*n):
y+=2
My logic is that the inner for loop will have this summation given the known solution of sum of i from 0 to n which n(n+1)/2:
(j*n)(j*n + 1)/2 #in this case, j*n is what we're summing to
Then, this inner loop would be looped from j=0 to n, which by that logic allows me to sum that from 0 to n:
( (n(n+1)/2) * n)((n(n+1)/2) * n + 1) / 2
Where I subbed j for (n(n+1)/2). After doing the multiplications I end up with
O(n^6)
I can't tell if my logic is sound or if I'm missing something because that number seems big. Thanks.
We can make a back of the envelope calculation.
j is ranging from 0 to n. So, the highest number for j is n. That is the absolute worst case for the inner loop.
So, the absolute worst case for the inner loop is if j == n, in which case the loop has j * n == n * n == n² iterations.
Meaning, the inner loop will in the absolute worst case have n² iterations. The outer loop, in turn, has n iterations, which means that our over-estimated, absolute worst-case upper bound is O(n³). It can't be worse than that. In fact, we have over-estimated by assuming that j * n == n², so we know it must definitely be less than n³.
Now, we can try to find an even more exact bound. In fact, we can actually find an exact number of iterations, we don't even need Bachmann-Landau notation.
Under the assumption that the loop bounds are exclusive, the statement in the inner loop will be executed (n³ - n²) / 2 times, and y will be n³ - n². (Says Wolfram Alpha.)

time complexity (with respect of n input)

I was asked if what time complexity if this:
What is the time complexity (with respect of n) of this algorithm:
k=0
for(i = n / 2 ; i < n ; i++ ) {
for( j=0 ; j < i ; j++)
k = k + n / 2
}
choices was : a. O(n) b. O(n/2) c. O(n log(n) and d. O(n^2)
can have a multiple answers.
i know the algorithm above is d. O(n^2) but i came with with a. O(n) since it is looking for complexity of n only?.
if you are to have this question. how would you answer it.?? im so curious about the answer.
The answer is O(n²).
This is easy to understand. I will try to make you understand it.
See, the outer for loop block is executed n - n/2 = n/2 times.
Of course it depends whether the number n is even or odd. If it's even then the outer loop is executed n/2 times. If it's odd then it's executed for (n-1)/2 times.
But for time complexity, we don't consider this. We just assume that the outer for loop is executed n/2 times where i starts from n/2 and ends at n - 1 (because the terminating condition is i < n and not i <= n).
For each iteration of the outer loop, the inner loop executes i times.
For example, for every iteration, inner loop starts with j = 0 to j = i - 1. This means that it executes i times (not i - 1 times because j starts from 0 and not from 1).
Therefore, for 1st iteration the inner loop is executed i = n / 2 times. i = n / 2 + 1 for 2nd iteration and so on upto i = n - 1 times.
Now, the total no. of times the inner loop executes is n/2 + (n/2 + 1) + (n/2 + 2) + ... + (n - 2) + (n - 1). It's simple math that this sums up to (3n² - n)/2 times.
So, the time complexity becomes O((3n² - n)/2).
But we ignore the n term because n² > n and the constant terms because for every n they will remain the same.
Therefore, the final time complexity is O(n²).
Hope this helps you understand.

Big-O complexity of a piece of code

I have a question in algorithm design about complexity. In this question a piece of code is given and I should calculate this code's complexity.
The pseudo-code is:
for(i=1;i<=n;i++){
j=i
do{
k=j;
j = j / 2;
}while(k is even);
}
I tried this algorithm for some numbers. and I have gotten different results. for example if n = 6 this algorithm output is like below
i = 1 -> executes 1 time
i = 2 -> executes 2 times
i = 3 -> executes 1 time
i = 4 -> executes 3 times
i = 5 -> executes 1 time
i = 6 -> executes 2 times
It doesn't have a regular theme, how should I calculate this?
The upper bound given by the other answers is actually too high. This algorithm has a O(n) runtime, which is a tighter upper bound than O(n*logn).
Proof: Let's count how many total iterations the inner loop will perform.
The outer loop runs n times. The inner loop runs at least once for each of those.
For even i, the inner loop runs at least twice. This happens n/2 times.
For i divisible by 4, the inner loop runs at least three times. This happens n/4 times.
For i divisible by 8, the inner loop runs at least four times. This happens n/8 times.
...
So the total amount of times the inner loop runs is:
n + n/2 + n/4 + n/8 + n/16 + ... <= 2n
The total amount of inner loop iterations is between n and 2n, i.e. it's Θ(n).
You always assume you get the worst scenario in each level.
now, you iterate over an array with N elements, so we start with O(N) already.
now let's say your i is always equals to X and X is always even (remember, worst case every time). how many times you need to divide X by 2 to get 1 ? (which is the only condition for even numbers to stop the division, when they reach 1).
in other words, we need to solve the equation
X/2^k = 1 which is X=2^k and k=log<2>(X)
this makes our algorithm take O(n log<2>(X)) steps, which can easly be written as O(nlog(n))
For such loop, we cannot separate count of inner loop and outer loop -> variables are tighted!
We thus have to count all steps.
In fact, for each iteration of outer loop (on i), we will have
1 + v_2(i) steps
where v_2 is the 2-adic valuation (see for example : http://planetmath.org/padicvaluation) which corresponds to the power of 2 in the decomposition in prime factor of i.
So if we add steps for all i we get a total number of steps of :
n_steps = \sum_{i=1}^{n} (1 + v_2(i))
= n + v_2(n!) // since v_2(i) + v_2(j) = v_2(i*j)
= 2n - s_2(n) // from Legendre formula (see http://en.wikipedia.org/wiki/Legendre%27s_formula with `p = 2`)
We then see that the number of steps is exactly :
n_steps = 2n - s_2(n)
As s_2(n) is the sum of the digits of n in base 2, it is negligible (at most log_2(n) since digit in base 2 is 0 or 1 and as there is at most log_2(n) digits) compared to n.
So the complexity of your algorithm is equivalent to n:
n_steps = O(n)
which is not the O(nlog(n)) stated in many other solutions but a smaller quantity!
lets start with worst case:
if you keep dividing with 2 (integral) you don't need to stop until you
get to 1. basically making the number of steps dependent on bit-width,
something you find out using two's logarithm. so the inner part is log n.
the outer part is obviously n, so N log N total.
A do loop halves j until k becomes odd. k is initially a copy of j which is a copy of i, so do runs 1 + power of 2 which divides i:
i=1 is odd, so it makes 1 pass through do loop,
i=2 divides by 2 once, so 1+1,
i=4 divides twice by 2, so 1+2, etc.
That makes at most 1+log(i) do executions (logarithm with base 2).
The for loop iterates i from 1 through n, so the upper bound is n times (1+log n), which is O(n log n).

Lower-bound Runtime of this pseudo-code

for i = 0 to n do
for j = n to 0 do
for k = 1 to j-i do
print (k)
I'm wondering about the lower-bound runtime of the above code. In the notes I am reading it explains the lower bound runtime to be
with the explanation;
To find the lower bound on the running time, consider the values of i, such that 0 <= i <= n/4 and values of j, such that 3n/4 <= j <= n. Note that for each of the n^2/16 different combinations of i and j, the innermost loop executes at least n/2 times.
Can someone explain where these numbers came from? They seem to be arbitrary to me.
There are n iterations of the first loop and for each of them n iterations of the second loop. In total these are n^2 iterations of the second loop.
Now if you only consider the lower quarter of possible values for i, then you have n^2/4 iterations of the inner loop left. If you also only consider the upper quarter of values for j then you have n^2/16 iterations of the inner loop left.
For each iteration of these constrained cases you have j-i >= 3n/4-n/4 = n/2 and therefore the most inner loop is iterated at least n/2 times for each of these n^2/16 iterations of the outer loops. Therefore the full number of iterations of the most inner loop is at least n^2/16*n/2.
Because we considered only specific iterations, the actual number of iterations is higher and this result is a lower bound. Therefore the algorithm is in Omega(n^3).
The values are insofar arbitrary that you could use many others. But these are some simple ones which make the argument j-i >= 3n/4-n/4 = n/2 possible. For example if you took only the lower half of the i iterations and the upper half of the j iterations, then you would have j-i >= n/2-n/2 = 0, leading to Omega(0), which is not interesting. If you took something like lower tenth and upper tenth it would still work, but the numbers wouldn't be as nice.
I can't really explain the ranges from your book, but if you attempt to proceed via the methodology below, I hope it would become more clear to find what is it that you are looking for.
The ideal way for the outer loop (index i) and the inner loop (index j) is as follows, since j - i >= 1 should be sustained, so that the innermost loop would execute (at least once in every case).
The performed decomposition was made because the range of j from i to 0 is ignored by the innermost loop.
for ( i = 0 ; i < n ; i ++ ) {
for ( j = n; j > i ; j -- ) {
for ( k = 1; k <= j - i ; k ++ ) {
printf(k);
}
}
}
This algorithm's order of growth complexity T(n) is:
Hence, your algorithm does iterate more than the algorithm above (j goes from n to 0).
Using Sigma Notation, you can do this:
Where c represent the execution cost of print(k), and c' is the execution cost of the occurring iterations that don't involve the innermost loop.

What is the running time complexity of this algorithm

What is the time complexity of this algorithm:
sum = 0
i = 1
while (i < n) {
for j = 1 to i {
sum = sum + 1
}
i = i*2;
}
return sum
I know that the while loop is O(logn), but what is the complexity of the for loop? Is it O(n) or O(logn)?
One way to analyze this would be to count up the number of iterations of the inner loop. On the first iteration, the loop runs one time. On the second iteration, it runs two times. It runs four times on the third iteration, eight times on the fourth iteration, and more generally 2k times on the kth iteration. This means that the number of iterations of the inner loop is given by
1 + 2 + 4 + 8 + ... + 2r = 2r + 1 - 1
Where r is the number of times that the inner loop runs. As you noted, r is roughly log n, meaning that this summation works out to (approximately)
2log n + 1 - 1 = 2(2log n) - 1 = 2n - 1
Consequently, the total work done by the inner loop across all iterations in O(n). Since the program does a total of O(log n) work running the outer loop, the total runtime of this algorithm is O(n + log n) = O(n). Note that we don't multiply these terms together, since the O(log n) term is the total amount of work done purely in the maintenance of the outer loops and the O(n) term is total amount of work done purely by the inner loop.
Hope this helps!

Resources