简体   繁体   中英

Finding the T(n) of An Algorithm

Okay so when my professor was going over it in class it seemed quite simple, but when I got to my homework I became confused. This is a homework example.

for (int i = 0; i < n; i++)    // I know this runs at T(n)
 for (int j = n - 1; j >= i; j--)
 cout << i << " " << j << endl; 

Here's an example I understand

for(int i=0; i<n-1; i++) {
  for(int j=i+1; j<n; j++) {
    1 Simple statement
   }

For that example I just plugged in 0, 1, and 2. For 0, it ran for n-1, at 1 for n-2 and at 2 n-3. So I think that for the homework example if I plugged in 0 it would run for n+1 since j has to be greater than or equal to i which is 0. If it's not obvious, i'm pretty confused. If anyone could show me how to solve it, that'd make my day. Thanks guys.

Let's dig into the functon. Let's pick some numbers.

say, n = 5

So our code looks like this (magical pseudo-code uses INCLUSIVE loops, not that it's too important)

(1)for i = 0 to 4
  (2)for j = 4 to i
     (3)print i j
  next
next

So this is a matter of preference, but usually loops are assumed to cost 1 simple statement per execution (comparison, and incrementation). So we'll assume that statements (1) and (2) have a cost of 2. Statement (3) has a cost of 1.

Now to determine T(n).

Our outer loop for i = 0 to 4 runs exactly n times. Our inner loop for j = 4 to i . . . We'll dig in there for a minute.

For our example with n = 5 loop (2) will execute like so

j = 4; i = 0;  j = 4; i = 1;  j = 4; i = 2;  j = 4; i = 3  j = 4; i = 4;
j = 3; i = 0;  j = 3; i = 1;  j = 3; i = 2;  j = 3; i = 3;
j = 2; i = 0;  j = 2; i = 1;  j = 2; i = 2;
j = 1; i = 0;  j = 1; i = 1;
j = 0; i = 0; 

So it makes this kind of pyramid shape, where we do 1 less iteration each time. This particular example ran 5 + 4 + 3 + 2 + 1 = 15 times.

We can write this down as SUM(i; i = 0 to n).

Which we know from precalc: = (1/2)(n)(n+1).

And (3) will execute the exact same number of times as that inner loop since it's the only statement. So our total runtime is going to be. . . COST(1) + COST(2) + COST(3) (2)(n) + 2(1/2)(n)(n+1) + (1/2)(n)(n+1)

We can clean this up to be

(3/2)(n)(n+1) + 2n = T(n).

That said, this assumes that loops cost 2 and the statement costs 1. It's usually more meaningful to say loops cost 0 and statements cost 1. If that were the case, T(n) = (1/2)(n)(n+1).

And givent that T(n), we know T(n) is O(n^2).

Hope this helps!

It's not that hard.

3 examples for single loops:

for (int i = 0; i < n; i++)
for(int i = 0; i < n-1; i++)
for(int i = 2; i < n-1; i++)

The first loop executs it's content n times ( i=0,1,2,3,...,n-1 ).
The same way, the second loop is just n-1 times.
The third would be n-3 because it starts not at 0, but 2
(and if n is less than 3, ie. n-3<0 , it won't execute at all)

In a nested loop like

for(int i = 0; i < n-1; i++) {
  for(int j = 0; j < n; j++) {
    //something
  }
}  

For each pass of the outer loop, the whole inner loop is executed, ie. you can multiply both single loop counts to get how often "something" is executed in total. Here, it is (n-1) * n = n^2 - n .

If the inner loop depends on the value of the outer loop, it gets a bit more complicated:

for(int i = 0; i < n-1; i++) {
  for(int j = i+1; j < n; j++) {
    //something
  }
}  

The inner loop alone is n - (i+1) times, the outer one n-1 times (with i going from 0 to n-2 ).
While there are "proper" ways to calculate this, a bit logical thinking is often easier, as you did already:

i-value => inner-loop-time
0 => n-1
1 => n-2
...
n-2 => n - (n-2+1) = 1  

So you´ll need the sum 1+2+3+...+(n-1) .
For calculating sums from 1 to x, following formula helps:

sum[1...x] = x*(x+1)/2  

So, the sum from 1 to n-1 is

sum[1...n-1] = (n-1)*(n-1+1)/2 = (n^2 - n)/2  

and that´s the solution for the loops above (your second code).

About the first code:
Outer loop: n
Inner loop: From n-1 down to i included, or the other way from i up to <=n-1 ,
or from i up to <n , that´s ni times

i >= innerloop
0 n
1 n-1
2 n-2
...
n-1 1

...and the sum from 1 to n is (n^2 + n)/2 .

One easy way to investigate a problem is to model it and look at resulting data.

In your case, the question is: how many iterations does the inner loop depending on the the value of the outer loop variable?

let n = 10 in [0..n-1] |> List.map (fun x -> x,n-1-x);;

The 1 line above is the model showing what happens. If you now look at the resulting output, you will quickly notice something...

val it : (int * int) list = [(0, 9); (1, 8); (2, 7); (3, 6); (4, 5); (5, 4); (6, 3); (7, 2); (8, 1); (9, 0)]

What is it you notice? For a given N you run the outer loop N times - this is trivial. Now we need to sum up the second numbers and we have the solution:

sum(N-1..0) = sum(N-1..1) = N * (N-1) / 2 .

So the total count of cout calls is N * (N-1) / 2.

Another easy way to achieve the same is to modify your function a bit:

int count(int n) {
   int c = 0;
   <outer for loop>
       <inner for loop>
           c++;
   return c;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM