9

According to Alex Martelli in O'Reilly's Python in a Nutshell, the complexity class O(n) + O(n) = O(n). So I believe it. But am confused. He explains it by saying that, "the sum of two linear functions of N is also a linear function of N."

According to wikipedia, in functional analysis a linear function is a linear map, an example of which would be f(x+y) = f(x) + f(y). Found what seems to be a simpler definition here simply stating, "a linear function is a function who's graph is a straight line." And it includes a few more examples that are less esoteric-looking than the wikipedia article ones.

y = f(x) = a + bx

and:

y = 25 + 5x

let x = 1
then
y = 25 + 5(1) = 30

let x = 3
then
y = 25 + 5(3) = 40

Maybe it would be fair to expect that the sum of two linear equations could be represented on a graph as a straight line which shows something similar to an average between the straight lines that would represent each one.

So am I understanding correctly that even though in the following two functions, the "complex" function takes three times as long to process as the "simple" one, they each function in big-O notation as O(n), because the arc of the processing time would be represented by a straight, diagonal line on a plot/graph, and the time difference would be represented by the fact that on a graphic representation, the angle of the more complex function would be sharper?

from timer import Timer

def complex(it):
    result = []
    for i in it:
        result.append(i)
    result.reverse()
    return result

def simple(it):
    result = list(it)

longlist = list(range(0, 1000000))

with Timer() as t:
    reverse_(longlist)
print "=> elapsed time reverse: %s." % t.secs

with Timer() as t:
    straight(longlist)
print "=> elapsed time straight: %s" % t.secs
Colonel Panic
  • 132,665
  • 89
  • 401
  • 465
MikeiLL
  • 6,282
  • 5
  • 37
  • 68

8 Answers8

17

Correct, O(n) + O(n) = O(n).

More specifically, O(n) + O(n) = 2 * O(n), but since Big O only cares about functions as they tend toward infinity, anything linear is denoted as O(n).

bryce
  • 3,022
  • 1
  • 15
  • 19
11

The statement is correct, because the addition of two linear functions is also a linear function. Take for example these two:

y = 6*x + 10
y = 20*x + 2

Add them together and you get:

y = 26*x + 12

Which is also a linear function! This holds for any two linear functions.

y = A*x + B
y = C*x + D
-----------
y = (A+C)*x + (B+D)
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • thank you! I hope you don't mind me adding a link which shows a graph representation of the formulas. – MikeiLL Jul 07 '14 at 23:47
  • Why are you adding the `y`s on the left-hand side of the equations? You have to different linear functions `f_1(x) = a*x + b` and `f_2(x) = c*x + d`. The sum of those two functions is `f(x) = f_1(x) + f_2(x) = (a + c)*x + (b + d)`. The assumption that the `y`s on the left hand-side are the same for both functions is wrong, so it doesn't seem to make any sense to add them to `2*y`. – Sven Marnach Jul 09 '14 at 21:42
  • @SvenMarnach of course you're right. I'll edit it; doesn't affect the conclusion though. – Mark Ransom Jul 09 '14 at 22:32
8

So even though in the following two functions, the "complex" function takes three times as long to process as the "simple" one, they each function in big-O notation as O(n), because the arc of the processing time would be represented by a straight, diagonal line on a plot/graph, even though the angle of the more complex function would be sharper?

Yes. The letter O is used because it refers to the order of a function. Linear functions are of the same order, O(n), O(3n), O(Cn) are all linear.

On the other hand, O(n^2), O(n^3), and O(n^C) are all polynomial functions (of degree 2, 3, C). Here (when dealing with algorithms), we often do start making a distinction between things like O(n^2) and O(n^5) -- even though they are both of the same order.

And O(2^n), O(3^n), and O(C^n) are exponential. You generally don't want to write an algorithm with exponential complexity (or worse).

David Titarenco
  • 32,662
  • 13
  • 66
  • 111
6

A good (the best?) way to go about it is to refer back to the mathematical definition of big-O:

enter image description here

In plain English:

These two statements are equivalent:

  • f is O(g)

  • The ratio of f(n) to g(n) as n increases tends to a nonnegative value.

In our case we have g(n) = n. Now if we let f(n) = f1(n) + f2(n) and assume both f1 and f2 are O(n), the limit above will equal α = α1 + α2 which itself must be greater than or equal to zero (since by definition α1 ≥ 0 and α2 ≥ 0). Therefore f1(n) + f2(n) is also O(n), by our definition.

Community
  • 1
  • 1
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • 3
    As such, `=` is definitely an abuse of notation. –  Jul 07 '14 at 22:49
  • 2
    @Rhymoid +1. It should be more like `O(f) = O(g)` to be on safe side with everything. – luk32 Jul 07 '14 at 22:51
  • 1
    The statement with the Greek symbols is eluding me. I'm also not really understanding where the `g(x) = x` comes from. X is a value, right? Do we mean that the (value of the) result of g(x) = x? – MikeiLL Jul 07 '14 at 23:36
  • @arshajii I think you need to drop the `n` from the first statement. –  Jul 08 '14 at 11:54
  • @Rhymoid Sorry, what do you mean exactly? – arshajii Jul 08 '14 at 11:55
  • @arshajii In the second statement, `n` is 'bound' or 'quantified' by `lim`, so it's clear what you mean by it. But in `f(n) \in O(g(n))`, the `n` has no clear meaning. `O(.)` takes a function and yields a set of functions; by `f(n)`, you actually just mean the function `f` (again, an abuse of notation ;)). –  Jul 08 '14 at 12:00
  • The new plain english translation of the statement contained in the image is much clearer now. But what exactly does `g` represent? – MikeiLL Jul 08 '14 at 16:43
  • @MikeiLL The _g_ is simply what's inside the O. In your case that's _n_ since you're asking about _O(n)_. – arshajii Jul 08 '14 at 16:51
  • Then why have a `g` at all not stick with n? And are we then saying `n(n) = n`, which is still totally confusing to me. – MikeiLL Jul 08 '14 at 17:07
  • @MikeiLL Because the more general _g_ is required in the actual definition of big-O. _g_ is simply a function of _n_, and in this case _g(n) = n_ (again, because we're dealing with _O(n)_). – arshajii Jul 08 '14 at 17:10
  • You mean `g is a function of n` like the way `__add__` is a function of `x` (a python variable)? – MikeiLL Jul 08 '14 at 17:31
  • 1
    This should be "lim sup" instead of "lim". The limit of f over g isn't required to exist. – Sven Marnach Jul 09 '14 at 21:54
3

Yes, this is because Big-O notation is not meant to be used for the calculations of absolute running time, but to describe behaviour of algorithms with growing input.

In other words, if you have some algo that works in O(3n) and O(n) and you increase n however you want both of them will run as much longer.

It just gives a notion if one algorithms will out-scale another one at some point of increasing the input.

Of course mathematically everything can be proven using definitions.

luk32
  • 15,812
  • 38
  • 62
3

Let's say the first O(n) is represented by an equation:

y1 = f1(x) = a1 + b1.x

and the second O(n) is represented by an equation:

y2 = f2(x) = a2 + b2.x

By adding the two sides,

y1 + y2 = f1(x) + f2(x) = (a1+a2) + (b1+b2).x

which shows that y1+y2 is also O(n).

R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

That's correct. So long as the line on the graph is a straight one, the function is O(n), regardless of the angle. A function takes linear time when you can say "this function takes x seconds for every input item." x in this case could be three, or nine, or a million, and it's still a linear function.

TheSoundDefense
  • 6,753
  • 1
  • 30
  • 42
2

Already there are a lot of good answers but I've not seen an answer from this angle. The sum of O(x) + O(y) is the worst of O(x) and O(y). in this case as both of them are linear, say x = C1n and y = C2n and C1 > C2. Thus x dominates the O() function and the big-O will be, O(C1n) => O(n)

Fallen
  • 4,435
  • 2
  • 26
  • 46
  • I think that what you are saying is that whichever function represents the worst case scenario dictates the big_o status, right? Would you translate and/or give an example of `C1n` and `C2n`? – MikeiLL Jul 08 '14 at 16:48
  • 1
    C1 and C2 are just 2 constants. – Fallen Jul 09 '14 at 17:20