Data Structures, Algorithms, & Applications in Java
Chapter 17, Exercise 51
We may perform a breadth-first or depth-first search in each component
of the graph. In each component, the first vertex that is visited
may be assigned to either set. The assignment of the remaining
vertices in the component is forced by the bipartite labeling requirement
that the end points of an edge have different labels. The code
below assigns the first vertex in each component the label 1.
It is a modified version of the code for breadth first search.
/** Label the vertices such that every edge connects
* a vertex with label 1 to one with label 2
* @return null iff there is no such labeling
* @return an array of labels when the graph has such a labeling */
public int [] bipartite()
{
// make sure this is an undirected graph
verifyUndirected("bipartite");
int n = vertices();
// create label array, default initial values are 0
int [] label = new int [n + 1];
// do a breadth first search in each component
ArrayQueue q = new ArrayQueue(10);
for (int v = 1; v <= n; v++)
if (label[v] == 0)
{// new component, label the vertices in this component
label[v] = 1;
q.put(new Integer(v));
while (!q.isEmpty())
{
// remove a labeled vertex from the queue
int w = ((Integer) q.remove()).intValue();
// mark all unreached vertices adjacent from w
Iterator iw = iterator(w);
while (iw.hasNext())
{// visit an adjacent vertex of w
int u = ((EdgeNode) iw.next()).vertex;
if (label[u] == 0)
{// u is an unreached vertex
q.put(new Integer(u));
label[u] = 3 - label[w]; // assign u the other label
}
else
// u already labeled
if (label[u] == label[w])
// both ends of edge assigned same label
return null;
}
}
}
// labeling successful
return label;
}
When the graph is bipartite,
each vertex of the graph is added to the queue exactly once.
Each vertex is also deleted from the queue exactly once. When a vertex
is deleted from the queue, all vertices adjacent to it are examined.
It takes Theta(n) time to find and examine the vertices
adjacent to vertex w when an adjacency matrix is used and
Theta(dw) when adjacency lists are used.
If the algorithm does not terminate early because of an exception
or because the graph is not bipartite, all vertices in the graph
get examined.
The total examination time is Theta(n2) when adjacency
matrices are used and Theta(e) when adjacency lists are used. The remainder
of the algorithm
takes O(n) time. Allowing for exceptions and
the fact that the algorithm may terminate early because
the graph is not bipartite, we see that the overall complexity
is O(n2) when adjacency matrices
are used and O(n+e)
when adjacency lists are used.
A test program, input, and output appear in the files
TestBipartite.*.