heretoinfinity
heretoinfinity

Reputation: 1746

Graph: time & space complexity of changing from edge list to adjacency list representation and vice versa

I am dealing with a directed graph and I was confused as to how Alberto Miranda's explanation on Quora arrived at the time complexity O(n+m) [I am assuming he means O(V+E) for vertices and edges].

One can convert the edge list L into a adjacency list representation A in time O(n+m). Then, one can perform the DFS on representation A in time O(n+m), for a total of O(n+m).

Here's my understanding of converting from one representation to the other:

For the conversion from edge list to adjacency list:

My understanding is that all we have to do is go through each edge and add to the adjacency list of that first vertex in each edge list thereby giving the time complexity of O(E). What am I missing? I assume that the n and m variables refer to vertices and edges respectively but feel free to correct me.

For the conversion from adjacency list to edge list:

I tried this conversion just to see if he were referring to the inverse conversion. To switch from the adjacency list, I would have to go through each vertex, V and then go through each of V's edges, E giving me O(V+E).

I wrote the code for it to check

Here's the graph I am representing: The caveat is that vertex 3 is not a key in the adjacency list representation and so isn't included in conversion from adjacency list to edge list.

graph being represented

from collections import defaultdict

class AdjacencyListGraph:
  def __init__(self):
    self.graph = defaultdict(list)

  def addEdge(self, u, v):
    self.graph[u].append(v)

class EdgeListGraph:
  def __init__(self):
    self.graph = []

  def addEdge(self, u, v):
    self.graph.append([u, v])

  def addAllEdgesAtOnce(self, edgeList):
    self.graph = edgeList



def edgeListToAdjacencyList(edgeListGraph):
  adjacencyListGraph = AdjacencyListGraph()

  for edge in edgeListGraph.graph:
    adjacencyListGraph.addEdge(edge[0], edge[1])

  return adjacencyListGraph

def adjacencyListToEdgeList(adjacencyListGraph):
  edgeListGraph = EdgeListGraph()

  for vertex in adjacencyListGraph.graph.keys():
    for child in adjacencyListGraph.graph[vertex]:
      edgeListGraph.addEdge(vertex, child)

  return edgeListGraph

edgeList = [
              [1, 2],
              [2, 3],
              [1, 3],
              [4, 1],
              [4, 5],
              [5, 6],
              [6, 4]
]

edgeListGraph = EdgeListGraph()
edgeListGraph.addAllEdgesAtOnce(edgeList)
adjacencyListGraph = edgeListToAdjacencyList(edgeListGraph)
print(adjacencyListGraph.graph)

# trying to reverse the conversion
convertedEdgeListGraph = adjacencyListToEdgeList(adjacencyListGraph)
print(convertedEdgeListGraph.graph)

Giving results

>>> defaultdict(<class 'list'>, {1: [2, 3], 2: [3], 4: [1, 5], 5: [6], 6: [4]})
>>> [[1, 2], [1, 3], [2, 3], [4, 1], [4, 5], [5, 6], [6, 4]]

So my conversions work.

These posts are related to adjacency lists but don't mention time complexity.

Post 1

Post 2

Upvotes: 2

Views: 2827

Answers (1)

Ali
Ali

Reputation: 335

My understanding is that all we have to do is go through each edge and add to the adjacency list of that first vertex in each edge list thereby giving the time complexity of O(E).

Converting an edge list to the adjacency list is indeed O(E). There are E edges, so there should be E operations. However, printing (or presenting) the adjacency list itself is O(V+E). Here is why.

Think of, if there was no edge between any vertex, you have to still go through every vertex and you will end up with something like this:

{1: [], 2: [], 3: [], 4: [],... v: []}

So V number of operations is a must. On top of it, you have to print neighboring vertices for each vertex, if edges do exist. You have to print the neighboring vertices in total E times. That sums to O(V+E).

To sum up: convert from edge list to adjacency list: O(E) presenting the adjacency list (independent from conversion): O(V+E)

Upvotes: 1

Related Questions