11

I know there are two ways to represent my graph: one is using a matrix, and the other one is using a list.

If I use a matrix, I have to flip all the bits in the matrix. Doesn't that take O(V^2) time?

If I use a list, wouldn't I have to traverse each list, one by one, and create a new set? That would seem to take O(V+E) time which is linear. Am I correct?

So, I got another question here. Consider, for example, that I use the Dijkstra algorithm on my graph (either a matrix or a list), and we use a priority queue for the data structure behind the scene. Is there any relation of graph representation and the use of data structure? Will it affect the performance of the algorithm?

Suppose I were to use a list for representations and a priority queue for the Dijkstra algorithm, would there be a difference between matrix and use priority queue for Dijkstra?

I guess it relates to makeQueue operation only? Or they don't have different at all?

pb2q
  • 58,613
  • 19
  • 146
  • 147
Timothy Leung
  • 1,407
  • 7
  • 22
  • 39
  • Traversal of adjacency lists does Not Happen in linear Time in General as E=O(V^2). – collapsar Apr 23 '13 at 07:26
  • @collapsar It *always* happens in linear time with relation to the vertices *and edges*. To define time complexity only on a part of the input (i.e. just vertices) (without explicitly stating it) seems somewhat illogical, *especially* when the time is directly related to another part of the input (but I can't argue that many people may define it as you did). And E = O(V^2) is for dense graphs. Sparse graphs are E = O(V). – Bernhard Barker Apr 23 '13 at 07:53
  • @dukeling you are right in pointing out that reducing the 'size' of a problem to a single scalar involves a lack of precision. otoh, big-Oh notation describes the worst case and, considering graphs, without additional constraints worst case means E=O(V^2). being precise, O(V^2) is not correct for edge reversal on an adjacency matrix either - if the representation sports a flag row-major vs. col-major, transposition is O(1). – collapsar Apr 23 '13 at 08:50

4 Answers4

26

Reversing the adjacency lists of a Directed Graph can be done in linear time. We traverse the graph only once. Order of complexity will be O(|V|+|E|).

  1. Maintain a HashMap of Adjaceny Lists where the key is the vertex label and the value is an ArrayList of adjacent vertices of the key vertex.
  2. For reversing, create a new HashMap of the same kind. Scan the original hash map and for each key you come across, traverse the corresponding list.
  3. For each vertex found in the value list, add a key in the new hashMap, putting the key of the original HashMap as an entry in the ArrayList corresponding to the new key in the new HashMap.
public static HashMap<Character,ArrayList <Character>> getReversedAdjLists(RGraph g)
{
    HashMap <Character, ArrayList<Character>> revAdjListMap = new HashMap <Character, ArrayList<Character>>();
    Set <Character> oldLabelSet = g.adjListMap.keySet();

    for(char oldLabel:oldLabelSet)
    {
        ArrayList<Character> oldLabelList = g.adjListMap.get(oldLabel);

        for (char newLabel : oldLabelList)
        {
            ArrayList<Character> newLabelList = revAdjListMap.get(newLabel);

            if (newLabelList == null)
            {
                newLabelList = new ArrayList<Character>();
                newLabelList.add(oldLabel);
            }
            else if ( ! newLabelList.contains(oldLabel))
            {
                newLabelList.add(oldLabel);
            }

            revAdjListMap.put(newLabel, newLabelList);
        }
    }

    return revAdjListMap;
}
Rama
  • 304
  • 3
  • 9
  • Good answer. I was initially trying to do this with a static 2D array, but the transposition of that matrix (to accomplish reversal) is O(n^2) I am pretty sure. – scottysseus Dec 08 '15 at 20:14
  • Is there any possibility of a constant space solution? Is it possible to reverse the graph in-place? – Amitrajit Bose Oct 17 '19 at 17:59
0

I think reversing the graph by traversing the list takes O(V2), since for each vertex you must add or delete (V-1) edges.

As for Dijkstra's algorithm, as I understand it, if you represent the graph as a matrix or list the algorithm takes O(V2), but some other data structures are faster. The fastest known is a Fibonacci heap, which gives O(E + VlogV).

Beta
  • 96,650
  • 16
  • 149
  • 150
  • How about if I keep two lists? The incoming edges list and outgoing edges list, this seems to be a good idea? – Timothy Leung Apr 23 '13 at 02:03
  • @TimothyLeung: Why? I don't see how that would give any advantage over one list of outgoing edges. – Beta Apr 23 '13 at 04:40
  • @Beta I imagine it would only be O(V^2) when the graph is dense. Consider no edges. You'd only do O(1) work at every vertex, thus O(V). Thus edges has to come into play in the complexity. – Bernhard Barker Apr 23 '13 at 07:27
  • @Dukeling: are you talking about reversal or Dijkstra? – Beta Apr 23 '13 at 13:55
  • @Beta [Reversal](http://en.wikipedia.org/wiki/Reverse_graph), as in reverse the direction of all the edges. It looks like you may have interpreted it as a [complement](http://en.wikipedia.org/wiki/Complement_graph) operation (removing all existing edges and creating edges where there didn't exist any). Maybe this is what OP wanted, I'm not sure. – Bernhard Barker Apr 23 '13 at 14:04
  • @Dukeling: the OP said "If I use matrix, I have to flip all bits in the matrix." I inferred that he meant the complement. If he meant reversing the direction of the edges, then yes, it's O(V+E) and keeping two lists might make a difference, depending on how it's implemented. – Beta Apr 23 '13 at 14:26
  • @Beta: Keeping a second list is unnecessary. As collapsar mentioned in the comments, reversing edge directions in a matrix can be accomplished by changing from row-major to col-major indexing (or vice-versa) by simply swapping the indices on each lookup. You can use the same logic for an adjacency list and search the (reversed) destination node's list for the (reversed) source node. If an edge exists from node p to node q in the original graph, an edge exists from node q to node p in the edge-direction-reversed graph. – beaker Apr 23 '13 at 14:51
  • By the way, just in case the OP really meant complement, you can use similar tricks without duplicating or transforming the matrix/list. – beaker Apr 23 '13 at 14:53
0
G = {"A":["B", "C","D"],"B":["C", "E"], "C":["D", "E"],"D":[],"E":["D"] }
res ={}
for k in G.keys():
    for val in G[k]:
        if val not in res.keys():
            res[val] = [k]
        else:
            res[val].append(k)

print(res)
0

Since I see a couple of comments asking about an in place graph transpose (reversal), here is my version of it. Please note this will only work on DAGs.Feedback and suggestions for improvement would be welcome

def transpose(G):
    """
    Return the transpose of a directed graph i.e. all the edges are reversed (In Place)
    """
    #note this is not a standard lib function afaik and you would have to 
    #implement topological sort but that should be easy
    topsort = topological_sort(G) 
    topsort.reverse() # we want to process starting from sink node
    for v in topsort:
        for node in G[v]:
            G[node].append(v)
        #  remove all older members of the vertex 'v'  
        G[v] = []
    print(G)
Abhas Sinha
  • 1,042
  • 1
  • 8
  • 9