Hashmap representation of graph

16,756

Solution 1

Among many possible representations of a graph, the 2 basic are the following:

  • Adjacency lists

enter image description here

In Java:

Map<Integer, List<Integer>> graph = new HashMap<>();
...
while( (line = bReader.readLine()) != null) {
    String[] tokens = line.split(" ");
    int firstNode = Integer.parseInt(tokens[0]);
    int secondNode = Integer.parseInt(tokens[1]);

    if(!graph.containsKey(firstNode)) graph.put(firstNode, new LinkedList());
    graphEdges.get(firstNode).add(secondNode);
}
  • Adjacency Matrix

enter image description here

In Java:

int[][] graph = new int[numberOfNodes][numberOfNodes];
while( (line = bReader.readLine()) != null) {
    String[] tokens = line.split(" ");
    int firstNode = Integer.parseInt(tokens[0]);
    int secondNode = Integer.parseInt(tokens[1]);

    graph[firstNode-1][secondNode-1] = 1;
    graph[secondNode-1][firstNode-1] = 1;
}

Below is a comparison of operations and storage efficiency of these 2 representations:

                   |     Adjacency List    |   Adjacency Matrix   |
Storage            |      O(nodes+edges)   |     O(nodes^2)       |
Add node           |          O(1)         |     O(nodes^2)*      |
Add edge           |          O(1)         |        O(1)          |
Remove node        |        O(edges)       |     O(nodes^2)*      |
Remove edge        |        O(edges)       |        O(1)          |
isAdjacent(x1,x2)  |        O(nodes)       |        O(1)          |
*Requires copying of the whole array

You can also make a slight modification in the adjacency lists and use HashSets, instead of LinkedList for storing the adjacent nodes. In that case, everything is the same, except the isAdjacent(x1,x2) operation that now has O(1) complexity (amortized).

Solution 2

A HashMap is not suited in this case since for a specified key you can have a single value. You need a map that can hold multiple values for a key. Guava has exactly this concept in Multimap with an implementations like ArrayListMultimap.

Solution 3

To produce a PNG like this:

enter image description here

or an XML (GraphML) like this:

<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
    <graph id="G" edgedefault="directed">
        <node id="Off" />
        <node id="Standby" />
        <node id="Fail" />
        <node id="Oper" />
        <node id="Recovery" />
        <node id="Shutdown" />
        <edge id="1" source="Off" target="Standby" />
        <hyperedge>
            <endpoint node=Standby" type="in" />
            <endpoint node=Fail" type="out" />
            <endpoint node=Oper" type="out" />
            <endpoint node=Shutdown" type="out" />
        </hyperedge>
        <hyperedge>
            <endpoint node=Fail" type="in" />
            <endpoint node=Shutdown" type="out" />
            <endpoint node=Recovery" type="out" />
        </hyperedge>
        <hyperedge>
            <endpoint node=Oper" type="in" />
            <endpoint node=Standby" type="out" />
            <endpoint node=Fail" type="out" />
            <endpoint node=Shutdown" type="out" />
        </hyperedge>
        <edge id="2" source="Shutdown" target="Off" />
        <hyperedge>
            <endpoint node=Recovery" type="in" />
            <endpoint node=Oper" type="out" />
            <endpoint node=Shutdown" type="out" />
        </hyperedge>
    </graph>
</graphml>

You may do it yourself too:

public abstract class Edge {
   protected final Node _endPoint1;
   public Edge( Node endPoint ) {
      _endPoint1 = endPoint;
   }
   public Node getEndPoint1() {
      return _endPoint1;
   }
}

class DirectedEdge:

public final class DirectedEdge extends Edge {
   private final Node[] _to;
   public DirectedEdge( Node from, Node ... to ) {
      super( from );
      _to = to;
   }
   public Node getFrom() {
      return _endPoint1;
   }
   public Node[] getTo() {
      return _to;
   }
}

class Graph:

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

public final class Graph {
   private /* */ String              _name = "G";
   private final Map< String, Node > _nodes = new LinkedHashMap<>();
   private final Set< DirectedEdge > _edges = new LinkedHashSet<>();

   public boolean addNode( Node node ) {
      return _nodes.put( node._label, node ) == null;
   }
   public void addEdge( DirectedEdge edge ) {
      _edges.add( edge );
   }
   public String getName() {
      return _name;
   }
   public void setName( String name ) {
      _name = name;
   }
   public final Map<String, Node> getNodes() {
      return _nodes;
   }
   public final Set<DirectedEdge> getEdges() {
      return _edges;
   }
}

class Main, example of use:

import java.io.File;

public class Main {
   private static Graph getGraph() {
      Graph graph = new Graph();
      Node off      = new Node( "Off" );
      Node standby  = new Node( "Standby" );
      Node fail     = new Node( "Fail" );
      Node oper     = new Node( "Oper" );
      Node recovery = new Node( "Recovery" );
      Node shutdown = new Node( "Shutdown" );
      graph.addNode( off );
      graph.addNode( standby );
      graph.addNode( fail );
      graph.addNode( oper );
      graph.addNode( recovery );
      graph.addNode( shutdown );
      graph.addEdge( new DirectedEdge( off     , standby ));
      graph.addEdge( new DirectedEdge( standby , fail, oper, shutdown ));
      graph.addEdge( new DirectedEdge( fail    , shutdown, recovery ));
      graph.addEdge( new DirectedEdge( oper    , standby, fail, shutdown ));
      graph.addEdge( new DirectedEdge( shutdown, off ));
      graph.addEdge( new DirectedEdge( recovery, oper, shutdown ));
      return graph;
   }
   public static void main( String[] args ) throws Exception {
      Graph graph = getGraph();
      new DotFileGenerator().save( new File( "States.png"     ), graph );
      new GraphMLGenerator().save( new File( "States.graphml" ), graph );
   }
}
Share:
16,756

Related videos on Youtube

user2081119
Author by

user2081119

Updated on September 14, 2022

Comments

  • user2081119
    user2081119 over 1 year

    I have a text file with graph edges, for example

    1 2

    1 3

    2 5

    etc. , and want to represent my graph in some way. I tried to use a hashmap, is it the best way to represent edges? And second question, how can I access first and second entries in my hashmap? My code here

        DataInputStream dStream = new DataInputStream(new FileInputStream("C:/Programming/Java/test.txt"));
        BufferedReader bReader = new BufferedReader(new InputStreamReader(dStream));
    
        HashMap<Integer, Integer> graphEdges = new HashMap<Integer, Integer>();
        String line;
        while( (line = bReader.readLine()) != null) {
            String[] firstSecond = line.split(" ");
            int firstDigit = Integer.parseInt(firstSecond[0]);
            int secondDigit = Integer.parseInt(firstSecond[1]);
    
            graphEdges.put(firstDigit, secondDigit);
        }
    
        System.out.println(graphEdges);
    
        bReader.close();
    }
    
    • Marco13
      Marco13 about 10 years
      As mentioned in the answers: Such a map is not appropriate here. You said that you want to "represent my graph in some way" - you should be more specific here. The efficiency (or even practical applicability) of most graph algorithms relies on a small subset of operations to be performed on the graph. The most common one: "Give me all neighbors of vertex X", or "Give me all edges with vertex X", ... You should think about which operations you need, and which structure is appropriate for that (maybe in a new, more detailled and focused question), or use an existing graph library.
  • JB Nizet
    JB Nizet over 11 years
    +1. Even without Guava, a Map<Integer, List<Integer>> could be used.
  • Benoît Guédas
    Benoît Guédas over 11 years
    @JB Nizet or Map<Integer, Set<Integer>>
  • dan
    dan over 11 years
    @JBNizet Yes, if he is not able to use a thirdparty library then such a map (or a map of tuples or multiple maps, depending on his context) is the way to go.
  • Zeno Raiser
    Zeno Raiser about 6 years
    the first implementation that you have written represents an Undirected graph right? If that's the case the image above with the arrows is a bit misleading
  • Dimos
    Dimos about 6 years
    @ZenoRaiser right, thanks for the catch. I updated the code to generate a directed graph to avoid confusion.