Selection sort CLRS - Correctness of the reasoning - algorithm

I'm a self-taught computer science student.
Now I'm reading CLRS and I did the 2.2-2 exercise, it's about Selection Sort.
First array subscript is 1.
The pseudocode that I wrote is:
FOR i=1 to A.length - 1
FOR j=i+1 to A.length
IF A[j] < A[i]
new_index=j
IF new_index > i
tmp = A[i]
A[i] = A[new_index]
A[new_index] = A[i]
My reasoning is:
the first loop test is executed n times (1, 2, 3 ... n). When i becomes n the loop stops. So line 5 is executed (n-1) times and so on.
Then I think that the second loop test is executed (n^2 + n - 2)/2 times. When initial j = 2, it assumes: 2, 3, 4, 5 ... (n + 1), the loop test is executed n times, when j = 3 the loop test is executed (n - 1) times and so on. So when j = n the loop test is executed 2 times.
For this reason the second loop test is executed:
2 + 3 + 4 + 5 + ... + n = [(n-1)*(n+2)] / 2 = (n^2 + n - 2) / 2.
So the inner if of the second loop is executed: 1 + 2 + 3 + 4 + ... + (n-1) = [(n-1)*n] / 2.
Before this written I read a lot of hypothetical solutions but no one is equal to mine. So I'd like to know if my reasoning is wrong.
I hope that I written all details in good form.

The pseudocode is right and your analysis is along the right lines, but your solution has some mistakes in its reasoning.
Some Tips
Then I think that the second loop test is executed (n^2 + n - 2)/2 times
It's executed n(n-1)/2 times. See the solution below.
When initial j = 2, it assumes: 2, 3, 4, 5 ... (n + 1), the loop test is executed n times,
Remember the code is: FOR j=i+1 to A.length, so when the inner for loop starts at j = 2, it goes up to j = A.length, i.e. it goes up to j = n. In other words, it executes repeatedly for j = 2, 3, 4, ..., n and so executes a total of n - 1 times, not n times!
For this reason the second loop test is executed: 2 + 3 + 4 + 5 + ... + n = [(n-1)*(n+2)] / 2 = (n^2 + n - 2) / 2. So the inner if of the second loop is executed: 1 + 2 + 3 + 4 + ... + (n-1) = [(n-1)*n] / 2.
Suppose the body of the if statement of the second loop is always executed (the if condition is always true), then it should execute the same number of times as the second loop test. So I don't follow your reasoning here. And as for the summation, to find number of iterations, you need to add up the following:
j = 1: executes (n-1) times
j = 2: executes (n-2) times
j = 3: executes (n-3) times
...
j = n: executes 1 time
So you need to add up: (n-1) + (n-2) + (n-3) + ... + 1 = n(n-1)/2
Solution
The inner for loop executes exactly C(n, 2) = n(n-1)/2 times. The loop produces all pairs (i,j) such that 1 <= i < j <= n – which from combinatorics is n-choose-2, or C(n, 2).
The if statement body (new_index=j) executes at most n(n-1)/2 times – we don't know exactly how many because we don't know what the values in A are – so we don't know how many times A[j] < A[i]. It could execute zero times (consider the case when the array is sorted). But nevertheless, we find an upper bound by assuming the condition is always true. In this worst case, the if statement's body executes the same number of times as the inner for loop – which from the previous bullet point is n(n-1)/2
By similar reasoning, the other if statement body (the one performing the swap) executes at most n times.
So overall, the algorithm performs exactly n(n-1)/2 iterations of the inner for loop iterations having ϴ(1) work – and exactly n iterations of the if statement performing a swap in ϴ(1) time. This gives a time complexity of ϴ(n^2).

Related

confused about the time complexity of the follwing func. A good explanation would be helpful

If the the first loop runs for n+1 times.
second loop runs for n(n+1) times.
third loop will run for ??? it has n^2+1 one relation with with with the second loop i guess but how about with the first one
somefunction(n) {
c = 0
for (i = 1 to n*n)
for (j = 1 to n)
for (k = 1 to 2*j)
c = c+1
return c
}
The first loop has O(n**2) iterations.
The second loop has O(n) iterations.
The third loop has O(n) iterations as well, since j is steadily increasing towards n.
(It's a little easier to see if you sum up the number of times c = c + 1 executes for the two inner loops combined. The inner loop runs 2 times for j = 1, 4 for j = 2, ..., and 2*n times for j = n. 2 + 4 + .. + 2*n = O(n**2).)
You can then (loosely speaking) multiply the three values together to get a total bound of O(n**4).

How to do this nested for loop time complexity?

I'm trying to figure out this time complexity:
for(i=0; i<=(n/2)-1; i++){
for (j=i+1; j<=(n/2)-1; j++){
--some O(1) thing--
}
}
The outer loop I understand to be on its own O(n/2.) However with the inner loop as well I can't wrap my brain around how to break down how many times O(1) executes.
If the inner one stared j=0 I could do n/2(inner) * n/2(outer) = O(n^2) time complexity right? However since j depends on i, I'm thinking some type of summation is involved from i+1 to n/2 but i can't figure out how to set it up...
Basically I need help kind of visualizing how many times it loops, and how to set the summation up. Thank you! :)
Assuming that m = n/2. You will see that in inner loop, j will iterater over range m-1, m-2, m-3,... 1. Summing all of that will be 1+2+..+m-1 = (m-1)*m/2 = O(m^2)
Premise
For simplicity, let us call m = n / 2 - 1. The outer loop runs from 0 to m. The inner loop from i + 1 to m.
Iteration counting
We need to count how often the inner statement which you labeled O(1) is executed. That is, how often the inner loop runs in total, as executed by the outer loop. So let us take a look.
The first iteration of the outer loop generates m - 1 iterations of the inner loop. The second generates m - 1, then m - 2, m - 3, m - 4, ..., 2, 1, 0.
That means that the O(1) statement is, in total, executed:
(m - 1) + (m - 2) + (m - 3) + ... + 2 + 1 + 0
That is the sum from 0 up to m - 1
sum_{i = 0}^{m - 1} i
which can be simplified to
(m^2 - m) / 2
Substitute back
Let us now substitute back m = n / 2 - 1, we get
((n / 2 - 1)^2 - (n / 2 - 1)) / 2
After simplifying, this is
n^2/8 - 3n/4 + 1
Big-O
For Big-O, we observe that it is smaller than
n^2 - 0 + n^2
= 2n^2
Which, by definition is O(n^2).
As you see, this bound is also tight. So we also receive Omega(n^2) which also concludes Theta(n^2).

Determining the time complexity

Given the following pseudo code for an array A
x = 0
for i = 0 to n - 1
for j = i to n - 1
if A[i] > A[j]:
x = x + 1
return x
how do I determine the running time?
I would say it's (n - 1)*(n - 1) = n^2 - 2n - 1 = O(n^2).
I'm not quite sure how to work with the if loop though.
yes O(n^2), just sum the number of iterations in the inner loop:
n + (n - 1) + (n - 2) + ... 1 = [ n x (n + 1) ] / 2
and if is not a loop, it is a control structure. generally you just count the number of times the condition is checked without considering the condition. The condition may be important if there is another loop in the if body.
how to count the iterations of the inner loop:
when i = 0 the inner loop runs n times, then ends
then i = 1 the inner loop runs n - 1 times, then ends
then i = 2 the inner loop runs n - 2 times, then ends
....
when i = n - 2 inner loop runs 1 times
when i = n - 1 inner loop runs 0 times
so all we need to do is to add the number of iterations of the inner loop:
n + (n - 1) + (n - 2) + ... 1 = [ n x (n + 1) ] / 2
#perreal is totally right about the order:
n*(n+1)/2 => O(n^2)
About the "if" part, it doesn't really matter. (I write this to answer to this part)
Lets say doing checking if takes c1 time, and doing the x=x+1 takes c2 time. You will have
(c1 | c1+c2)* n*(n+1)/2
And since you can ignore the constants from the order, it is from
O(n^2)
Actually, saying "this algorithm has a O(n^2)time complexity" suggests implicitly that it's a worst case complexity.
In a naive way, you can just count the number of times each instruction is executed in the worst case. if A[i] > A[j]: might be considered as an instruction as well, so first you don't necessarily have to ask yourself when the condition is true.
2*(n-1)*(n-1) is a majorant of the number of instructions executed in the inner-most loop, and more precisely:
2(n + (n-1) + ... + 1) = n(n+1) = O(n^2)
Even if it's not important with the O-notation, there are several arrays for which the condition is always true (thus these are the worst case for this algorithm). For example:
n n-1 n-2 ... 2 1

time complexity calculation for two for loops with connecting variables

what would be the time coplexity of this:
for(k=1;K<=n;k*=2)
for(j=1;j<=k;j++)
sum++
For this i thought as
1. Outer Loop will run logn times
2. Inner Loop will also run logn times.because i think inner loop j is related to k. So how much ever k runs, same is the running time for j too. So total = O(logn * logn)
but in text they have given total= O(2n-1).
can you please explain
when k is 1 (sum++) runs 1 times
when k is 2 (sum++) runs 2 times
when k is 4 (sum++) runs 4 times
when k is n = 2^k (sum++) runs 2^k times
so we must calculate
1+2+4+ ... + 2^k = 2^0 + 2^1 + 2^2 + .... + 2^k = (1 - 2^(k+1))/(1-2)
because we put n = 2^k so :
k = log(n)
2^(log(n)) = n^(log(2))
2* 2^k -1 = 2*n - 1
This problem is most easily interpreted by forgetting that the outer loop is there and first looking at the inner loop complexity. Suppose that the inner loop runs 'M' times... then the total number of 'sum++' operations will be,
1 + 2 + 4 + ... + 2^(M-1)
This sum can be reduced to '2^(M) - 1' by noticing that this is a binary number composed of all 1's. Now the question is what is M? You've already figure this out, M = log(n)+1 (the +1 is because the loop must run at least once). Plugging this into the inner loop complexity leaves us with,
2^(log(n)+1)-1 = 2*n - 1.
Thus the entire loop scales as O(2n-1). Hope this helps!

complexity theory-sorting algorithm

I'am taking a course in complexity theory,and so it's need some mathematical background which i have a problem,.
so while i'am trying to do some practicing i stuck in the bellow example
1) for (i = 1; i < n; i++) {
2) SmallPos = i;
3) Smallest = Array[SmallPos];
4) for (j = i+1; j <= n; j++)
5) if (Array[j] < Smallest) {
6) SmallPos = j;
7) Smallest = Array[SmallPos]
}
8) Array[SmallPos] = Array[i];
9) Array[i] = Smallest;
}
Thus, the total computing time is:
T(n) = (n) + 4(n-1) + n(n+1)/2 – 1 + 3[n(n-1) / 2]
= n + 4n - 4 + (n^2 + n)/2 – 1 + (3n^2 - 3n) / 2
= 5n - 5 + (4n2 - 2n) / 2
= 5n - 5 + 2n^2 - n
= 2n^2 + 4n - 5
= O(n^2)
and what i don't understand or confused about line 4 analyzed to n(n+1)/2 – 1,
and line 5 3[n(n-1) / 2].
i knew that the sum of positive series is =n(first+last)/2 ,but when i tried to calculate it as i understand it it gives me different result.
i calculate for line no 4 so it shoulb be =n((n-1)+2)/2 according to n(first+last)/2 ,but here it's n(n+1)/2 – 1.
and same for 3[n(n-1) / 2].....i don't understand this too
also here's what is written in the analysis it could help if anyone can explain to me,
Statement 1 is executed n times (n - 1 + 1); statements 2, 3, 8, and 9 (each representing O(1) time) are executed n - 1 times each, once on each pass through the outer loop. On the first pass through this loop with i = 1, statement 4 is executed n times; statement 5 is executed n - 1 times, and assuming a worst case where the elements of the array are in descending order, statements 6 and 7 (each O(1) time) are executed n - 1 times.
On the second pass through the outer loop with i = 2, statement 4 is executed n - 1 times and statements 5, 6, and 7 are executed n - 2 times, etc. Thus, statement 4 is executed (n) + (n-1) +... + 2 times and statements 5, 6, and 7 are executed (n-1) + (n-2) + ... + 2 + 1 times. The first sum is equal to n(n+1)/2 - 1, and the second is equal to n(n-1)/2.
Thus, the total computing time is:
T(n) = (n) + 4(n-1) + n(n+1)/2 – 1 + 3[n(n-1) / 2]
= n + 4n - 4 + (n^2 + n)/2 – 1 + (3n^2 - 3n) / 2
= 5n - 5 + (4n2 - 2n) / 2
= 5n - 5 + 2n^2 - n
= 2n^2 + 4n - 5
= O(n^2)
here's the link for the file containing this example:
http://www.google.com.eg/url?sa=t&rct=j&q=Consider+the+sorting+algorithm+shown+below.++Find+the+number+of+instructions+executed+&source=web&cd=1&cad=rja&ved=0CB8QFjAA&url=http%3A%2F%2Fgcu.googlecode.com%2Ffiles%2FAnalysis%2520of%2520Algorithms%2520I.doc&ei=3H5wUNiOINDLswaO3ICYBQ&usg=AFQjCNEBqgrtQldfp6eqdfSY_EFKOe76yg
line 4: as the analysis says, it is executed n+(n-1)+...+2 times. This is a sum of (n-1) terms. In the formula you use, n(first+last)/2, n represents the number of terms. If you apply the formula to your sequence of n-1 terms, then it should be (n-1)((n)+(2))/2=(n²+n-2)/2=n(n+1)/2-1.
line 5: the same formula can be used. As the analysis says, you have to calculate (n-1)+...+1. This is a sum of n-1 terms, with the first and last being n-1 and 1. The sum is given by (n-1)(n-1+1)/2. The factor 3 is from the 3 lines (5,6,7) that are each being done (n-1)(n)/2 times

Resources