3

Correct me if my thinking is wrong. I think that BigO(V + E) = BigO(V^2).

Below is my thinking:
Edges in a complete graph = n*(n-1)/2.

Switching from E and V to n because it is easier for me to think that way.

E = n*(n-1)/2
V = n

BigO(V + E) => BigO(n + n*(n-1)/2) => BigO(n^2)

Switching n back to V.

=> BigO(v^2)

am I missing something? Why use BigO(V + E)? Why not use BigO(V^2)?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
bluejimmy
  • 390
  • 6
  • 14
  • 1
    |E| = |V|*(|V|-1) / 2 only if the graph is a clique. If it's not a clique then |E| < |V|*(|V|-1) / 2, and in fact can be much smaller on sparse graphs. – Tony Tuttle Aug 04 '16 at 14:09
  • 2
    No. O(V^2) ignores the fact that the function grows as E increases for fixed values of V. This is not a question of "worst case" either as the worst case is the input on which the algorithms performs the worst compared to another input of the *same size*. – beaker Aug 04 '16 at 14:32
  • @beaker Could you explain why the worse case doesnt apply here? The input of edges can vary, no? – bluejimmy Aug 04 '16 at 15:13
  • 1
    Yes, that comment is a bit out of context now as it was originally written in response to a now-deleted answer. I meant that you cannot say "the complexity is O(V^2) because in the worst case there will be O(V^2) edges." Changing the number of edges changes the size of the input. Therefore, it's not a "worst case", it's simply the same case on a larger data set. – beaker Aug 04 '16 at 15:18
  • BTW, you can have multi-edges in general graph, so if you have V edges for every (A,B) in "complete" graph, then E = V*V*(V-1)/2. Or in in minimum connected tree (not sure what's the proper English term, in my language we call that one "skeleton" :) ) the E is only V-1. (my mistake: OH... adjacency list is still V*(V-1)/2 at most, of course, unless you take into account also direction of edge, or some other artificial extra constraint) – Ped7g Aug 04 '16 at 19:09

3 Answers3

5

The memory usage of an adjacency list is directly proportional to the sum of the number of nodes and the number of edges. This is because each node has an associated list of the edges leaving it, and each edge appears at most twice (once for each node it touches in an undirected graph, or once for a directed graph). This means that the space usage is Θ(V + E).

You gave two different asymptotic bounds on the memory usage, O(V + E) and O(V2). Both of these bounds are correct, but one is tighter than the other. The O(V + E) bound more precisely indicates that there are two semi-independent quantities that go into the space usage, the number of nodes and the number of edges, and is more precise. The O(V2) bound is less precise, but gives a worst-case bound on the total memory usage by considering the maximum possible value of E in terms of V. In other words, the O(V + E) bound is much more useful if you're trying to precisely pin down the memory usage, but the O(V2) bound is better if you're worried about the worst-case memory usage.

(A quick note: the statement "an adjacency list is O(V + E)" isn't a meaningful sentence. Since big-O quantifies growth rates of functions, it would be like saying "an adjacency list is 95,201" - it's meaningless because you're comparing an object with a number. However, you can say "the space usage of an adjacency list is O(V + E)" because the space usage of an adjacency list is an actual numeric quantity.)

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
3

BigO is used for estimating how much <time, memory, whatever resource> you will use based on the input size.

When you're building adjacency list you know number of vertex V and number of edges E. Now you want to estimate how much memory you need.

O(V+E) can be interpreted as V > E ? O(V) : O(E) what means: it'll be linearly complex to max(V,E).

You create a list for each v, so you use O(V) memory on it. You mark each edge and this uses O(E) memory. O(V+E) means exactly that. If you would say that the complexity is O(V^2) it would mean that for an empty graph with 2*n vertex you should use approx. 4 time more memory than for an empty graph with n vertex.

When doing some research on complexity you can test different approach:

  • Worst case,
  • Average case,
  • Best case.

Read about different approaches to the topic and comment if you wish to receive some more information.

EDIT

According to the formal definition, O(V+E), O(V^2), O(V^3) and O(V^V^V) are still correct. In BigO we try to find the function which grows slowest but still is BigO with your complexity.

xenteros
  • 15,586
  • 12
  • 56
  • 91
1

Both statements are correct. They are not contradictory.

Over arbitrary graphs, resource usage is O(V2). But in a problem domain where sparse graphs are likely, resource usage is O(V+E). That provides more information.

Adjacency lists are generally used in problem domains where graphs are likely to be sparse. For dense graphs, arrays are usually a better solution. If you are considering two possible algorithms to solve a graph problem, you need to take into account what you know about the graphs. Is the out-degree constrained? In that case, an adjacency-list representation and associated algorithms may be a better solution.

Complexity analysis is not just a theoretical game. It is a way to organize your thinking about practical solutions to real programming problems.

rici
  • 234,347
  • 28
  • 237
  • 341
  • 1
    As graphs get denser, E approaches V^2. I would say you gain nothing by calling it O(V^2) rather than the tighter upper bound of O(V + E). – beaker Aug 04 '16 at 16:08
  • @beaker: if you know nothing about the graphs and you want to comparw with an array-based algorithm, O(V²) is simpler. Sometimes it is useful ti be able to analyze in terms of a single variable. But whatever. – rici Aug 04 '16 at 18:43