Graph and its representations
http://algs4.cs.princeton.edu/41undirected/Graph.java.html
http://opendatastructures.org/ods-java/12_2_AdjacencyLists_Graph_a.html
Use adjacent list
An array of linked lists is used. Size of the array is equal to number of vertices. Let the array be array[]. An entry array[i] represents the linked list of vertices adjacent to the ith vertex. This representation can also be used to represent a weighted graph. The weights of edges can be stored in nodes of linked lists.
Pros: Saves space O(|V|+|E|) . In the worst case, there can be C(V, 2) number of edges in a graph thus consuming O(V^2) space. Adding a vertex is easier.
Cons: Queries like whether there is an edge from vertex u to vertex v are not efficient and can be done O(V).
X. Use Map<Integer, List<Integer>> for unweighted graph.
https://gist.github.com/tnhansel/11441647
https://algocoding.wordpress.com/2014/08/24/adjacency-list-representation-of-a-graph-python-java/
ArrayList<ArrayList<Integer>> adjLists = new ArrayList<ArrayList<Integer>>();
http://algs4.cs.princeton.edu/41undirected/AdjMatrixGraph.java.html
Use adj Matrix
Adjacency Matrix is a 2D array of size V x V where V is the number of vertices in a graph. Let the 2D array be adj[][], a slot adj[i][j] = 1 indicates that there is an edge from vertex i to vertex j. Adjacency matrix for undirected graph is always symmetric. Adjacency Matrix is also used to represent weighted graphs. If adj[i][j] = w, then there is an edge from vertex i to vertex j with weight w.
Pros: Representation is easier to implement and follow. Removing an edge takes O(1) time. Queries like whether there is an edge from vertex ‘u’ to vertex ‘v’ are efficient and can be done O(1).
Cons: Consumes more space O(V^2). Even if the graph is sparse(contains less number of edges), it consumes the same space. Adding a vertex is O(V^2) tim
http://algs4.cs.princeton.edu/41undirected/Graph.java.html
http://opendatastructures.org/ods-java/12_2_AdjacencyLists_Graph_a.html
Use adjacent list
An array of linked lists is used. Size of the array is equal to number of vertices. Let the array be array[]. An entry array[i] represents the linked list of vertices adjacent to the ith vertex. This representation can also be used to represent a weighted graph. The weights of edges can be stored in nodes of linked lists.
Pros: Saves space O(|V|+|E|) . In the worst case, there can be C(V, 2) number of edges in a graph thus consuming O(V^2) space. Adding a vertex is easier.
Cons: Queries like whether there is an edge from vertex u to vertex v are not efficient and can be done O(V).
X. Use Map<Integer, List<Integer>> for unweighted graph.
https://gist.github.com/tnhansel/11441647
/* Makes use of Map collection to store the adjacency list for each vertex.*/private Map<Integer, List<Integer>> Adjacency_List;public GraphAdjacencyList(int number_of_vertices){Adjacency_List = new HashMap<Integer, List<Integer>>();for (int i = 1 ; i <= number_of_vertices ; i++){Adjacency_List.put(i, new LinkedList<Integer>());}}public void setEdge(int source , int destination){if (source > Adjacency_List.size() || destination > Adjacency_List.size()){System.out.println("the vertex entered in not present ");return;}List<Integer> slist = Adjacency_List.get(source);slist.add(destination);List<Integer> dlist = Adjacency_List.get(destination);dlist.add(source);}
https://algocoding.wordpress.com/2014/08/24/adjacency-list-representation-of-a-graph-python-java/
ArrayList<ArrayList<Integer>> adjLists = new ArrayList<ArrayList<Integer>>();
http://algs4.cs.princeton.edu/41undirected/AdjMatrixGraph.java.html
Use adj Matrix
Adjacency Matrix is a 2D array of size V x V where V is the number of vertices in a graph. Let the 2D array be adj[][], a slot adj[i][j] = 1 indicates that there is an edge from vertex i to vertex j. Adjacency matrix for undirected graph is always symmetric. Adjacency Matrix is also used to represent weighted graphs. If adj[i][j] = w, then there is an edge from vertex i to vertex j with weight w.
Pros: Representation is easier to implement and follow. Removing an edge takes O(1) time. Queries like whether there is an edge from vertex ‘u’ to vertex ‘v’ are efficient and can be done O(1).
Cons: Consumes more space O(V^2). Even if the graph is sparse(contains less number of edges), it consumes the same space. Adding a vertex is O(V^2) tim
public class AdjMatrixGraph {
private int V;
private int E;
private boolean[][] adj;
public AdjMatrixGraph(int V) { if (V < 0) throw new RuntimeException("Number of vertices must be nonnegative"); this.V = V; this.E = 0; this.adj = new boolean[V][V];
public void addEdge(int v, int w) { if (!adj[v][w]) E++; adj[v][w] = true; adj[w][v] = true; } // does the graph contain the edge v-w? public boolean contains(int v, int w) { return adj[v][w]; }
public Iterable<Integer> adj(int v) { return new AdjIterator(v); } // support iteration over graph vertices private class AdjIterator implements Iterator<Integer>, Iterable<Integer> { int v, w = 0; AdjIterator(int v) { this.v = v; } public Iterator<Integer> iterator() { return this; } public boolean hasNext() { while (w < V) { if (adj[v][w]) return true; w++; } return false; } public Integer next() { if (hasNext()) { return w++; } else { throw new NoSuchElementException(); } } public void remove() { throw new UnsupportedOperationException(); } }http://www.stoimen.com/blog/2012/08/31/computer-algorithms-graphs-and-their-representation/
In case that we’re using adjacency matrix we have:
- Adding an edge – O(1);
- Deleting an edge – O(1);
- Answering the question “is there an edge between i and j” – O(1);
- Finding the successors of a given vertex – O(n);
- Finding (if exists) a path between two vertices – O(n2);
While for an adjacency list we can have:
- Adding an edge – O(log(n));
- Deleting an edge – O(log(n));
- Answering the question “is there an edge between i and j” – O(log(n));
- Finding the successors of a given vertex – O(k), where “k” is the length of the lists containing the successors of i;
- Finding (if exists) a path between two vertices – O(n+m) – where m <= n;
We now see that depending of the representation of the graph we can have different complexities for the same operations. This is very important while trying to solve a problem and can be crucial while chosing the algorithm.