I heard that adjacency lists are used in most graph algorithms (but not all). I'm just wondering what algorithms prefer adjacency matrices and why?
So far I’ve found that Floyd Warshall uses adjacency matrices.
Adjacency lists are generally faster than adjacency matrices in algorithms in which the key operation performed per node is “iterate over all the nodes adjacent to this node.” That can be done in time O(deg(v)) time for an adjacency list, where deg(v) is the degree of node v, while it takes time Θ(n) in an adjacency matrix. Similarly, adjacency lists make it fast to iterate over all of the edges in a graph - it takes time O(m + n) to do so, compared with time Θ(n2) for adjacency matrices.
Some of the most-commonly-used graph algorithms (BFS, DFS, Dijkstra’s algorithm, A* search, Kruskal’s algorithm, Prim’s algorithm, Bellman-Ford, Karger’s algorithm, etc.) require fast iteration over all edges or the edges incident to particular nodes, so they work best with adjacency lists.
You mentioned that Floyd-Warshall uses adjacency matrices. While Floyd-Warshall does maintain an internal matrix tracking shortest paths seen so far, it doesn’t actually require the original graph to be an adjacency matrix. The overall cost of the dynamic programming work is Θ(n3), which is bigger than the O(n2) cost of converting an adjacency list into an adjacency matrix or vice-versa.
There are only a few places where an adjacency matrix is faster than an adjacency list. Adjacency matrices take time O(1) to test whether a particular edge is present in the graph, which is faster than the O(deg(v)) cost of the corresponding operation on an adjacency list. Since the cost of converting an adjacency list to an adjacency matrix is Θ(n2), the only cases where an adjacency matrix would outperform an adjacency list are in situations where (1) random access of the edges are required and (2) the total runtime of the algorithm is o(n2). I only know a few algorithms that do this. For example, there’s the celebrity-finding problem where you’re given a graph and are asked to find whether there’s a node with incoming edges from each node and outgoing edges to no nodes. This can be done in time O(n) using an adjacency matrix, faster than what can be done with an adjacency list.
(That being said, you could also use an adjacency list represented using cuckoo hash tables rather than regular lists and match the same runtime bounds as above, though with the cost of creating the adjacency list now only expected to be fast rather than actually worst-case efficient.)
The main reason I’ve found adjacency matrices to be useful is in thinking about graphs from a different perspective. For example, raising an adjacency matrix to the kth power makes a new matrix that counts the number of paths from one node to another using exactly k hops. This can be used to count and find triangles in graphs faster than the naive algorithm, for example. Similarly, the Four Russians algorithm for computing transitive closures of graphs works by representing the graph as a matrix and using some clever techniques (treating blocks of bits as integers then used in a lookup table) to outperform the naive search.
Hope this helps!
Related
I have understood and implemented Prim's and Kruskal's algorithm using adjacency matrix but I am not understanding how to write a program using adjacency lists
I tried creating 2 matrices one for min weight for each edge and which is a two dimensional matrix and another matrix for the visited edges. But I couldn't proceed with that approach. Please provide an approach.
Creating a two-dimensional matrix from the adjacency lists is not needed. It would be the same as using adjacency matrix.
You should either sort a list of all edges by their weights (in Kruskal's algorithm), or use a heap to find a minimal vertex (in Prim's algorithm).
For a graph with v vertices and e edges, and a fringe stored in a binary min heap, the worst case runtime is O((n+e)lg(n)). However, this is assuming we use a adjacency linked list to represent the graph. Using a adjacency matrix takes O(n^2) to traverse, while a linked list representation can be traversed in O(n+e).
Therefore, would using the matrix to represent the graph change the runtime of Dijkstra's to O(n^2lg(n))?
The O(log n) cost is paid for processing edges, not for walking the graph, so if you know the actual number of edges in the graph then Dijkstra's algorithm on an adjacency matrix with min-heap is within O(n^2 + (n+e)log(n)) time.
I was wondering, what is the most efficient way of storing the graph in a text file while you are implementing Dijkstra's algorithm? (Adjacency matrix, incidence matrix? etc)
In the general case, a good approach is to store a list of all edges.
It takes O(E) space: we store two endpoints per edge.
To store it on disk, that will suffice.
To work with such a list, it is usually stored in memory as V adjacency lists, one for every vertex.
This duplicates each edge (u->v and v->u) if the graph is undirected.
However, a common operation for graph algorithms is to traverse all edges from a given vertex.
By storing an adjacency list for each vertex, we get to do that in O(number of neighbors), which is the best possible.
Adjacency matrix takes O(V^2) space, which might be fine for dense graphs, but is worse than O(E) in the general case.
Incidence matrix takes O(VE) space, and is not efficient, unless your graph is somehow very special to make it so.
The fastest implementations of Dijkstra's algorithm take O(E log V) time, so O(E) memory is usually fine.
I found that there are two ways to implement Prim algorithm, and that the time complexity with an adjacency matrix is O(V^2) while time complexity with a heap and adjacency list is O(E lg(V)).
I'm wondering can I use a heap when graph is represented with adjacency matrix. Does it make sense? If it does, is there any difference between adjacency matrix + heap and adjacency list + heap?
Generally, the matrix graph-representation is not so good for Prim's algorithm.
This is because of the main iteration of the algorithm, which pops out a node from the heap, and then scans its neighbors. How do you find its neighbors? Using the matrix graph representation, you basically need to loop over an entire matrix row (in the list graph-representation, you just need to loop over the node's list, which can be significantly shorter).
This means that, irrespective of the heap, just the sum of the part of finding the neighbor's of the popped node is already Ω(|V|2), as each node's row is eventually scanned.
So, no - it doesn't make much sense. The heap does not reduce the overall complexity.
Are there any algorithms for which adjacency matrices outperform adjacency lists? What about vice versa?
In terms of Running Time, Adjacency Matrix would almost always outperform lists. The List implementation would use less memory(proportional to number of edges) to store the Graph.
So if memory does matter(it surely would with sparse Graphs with large number of nodes), use lists. If run time matters, and the Graph is likely to be dense, use Adjacency Matrix.