如何在Java中实现二部图? 更新
到目前为止,一些答案建议使用邻接列表。在Java中,邻接列表是什么样子的。。。没有指针对:)如何在Java中实现二部图? 更新,java,data-structures,graph,bipartite,Java,Data Structures,Graph,Bipartite,到目前为止,一些答案建议使用邻接列表。在Java中,邻接列表是什么样子的。。。没有指针对:) 我试图用Java实现一个二部图,将文件中的信息分成两组。我找到了这个例子,它确实起到了作用: 但是,我想实现我自己的版本。。。如果你看看a,你就会明白我为什么要自己做这件事 所以我必须读一个文件,从中我可以很容易地得到顶点的数量,但是边的数量却不那么容易。一个示例行是“PersonA PersonB”,可以理解为“PersonA说PersonB”。所以读这些句子 "A says B" "C says
我试图用Java实现一个二部图,将文件中的信息分成两组。我找到了这个例子,它确实起到了作用: 但是,我想实现我自己的版本。。。如果你看看a,你就会明白我为什么要自己做这件事 所以我必须读一个文件,从中我可以很容易地得到顶点的数量,但是边的数量却不那么容易。一个示例行是“PersonA PersonB”,可以理解为“PersonA说PersonB”。所以读这些句子
"A says B"
"C says B"
"D says B"
"B says D"
"E says A & C"
。。。生成此分组:
{A,D,C} and {B,E}.
我将如何实现这个二部图?什么是完成此任务的好资源?在创建二分图类时,我应该考虑什么事情(算法)。。。可能是遍历/排序算法?有向图是连接节点A和B的边具有方向的图;如果存在从A到B的边,这并不意味着存在从B到A的边。在您的示例中,边具有方向。(B到D是两条边,一条从B到D,一条从D到B。) 实现这一点的一种方法类似于链表,节点之间有适当的引用。回到您的示例,
nodeA
将引用nodeB
,但不是相反nodeE
将引用nodeA
和nodeC
,依此类推。您实际上是在创建一种(某种)数据结构,它具有节点和边缘的概念。你有很多方法可以做到这一点
一个可能的Java实现是有一个名为AdjacencyList
的类,该类有一个Map
包含一个顶点及其相邻顶点<代码>邻接列表将能够在其映射上执行操作
至于算法和需要记住的事情,请看一下二部图的性质,特别是
- 图是二部的当且仅当它不包含奇数圈。因此,二部图不能包含大小为3或更多的团
- 每棵树都是二部的
- 顶点数为偶数的圈图是二部图
一个好的测试是实现一个2-着色算法,以确认图确实是二部图。深度优先搜索、广度优先搜索是很好的实现练习。使用邻接列表实现应该非常简单。如果它是一个无向二部图,我建议使用关联矩阵 因此,对于每个节点,都有一个链表数组,或者一个动态分配列表数组。它应该使添加边变得相当自然,例如,在您的示例中,您有一条边: 人员A->人员B 然后,您将转到对应于人物A的数组索引,并向后推对应于人物B的索引: [人A]=人B 那也许你会获得另一个优势 人物角色A->人物角色C 那么您的索引将如下所示: 【人物A】=人物B、人物C 最后一个示例是示例图的邻接列表: [A] B [B] D [C] B [D] B [E] A,C 每个索引都有一个可从该节点访问的节点列表 “在创建BipartiteGraph类时,我应该考虑和思考哪些事情(算法)……可能是遍历/排序算法?” 这真的取决于你想用图形做什么 供参考: 1.)选择随机节点。把它放在二分图的“左边” 2.)选择与在1中选择的节点相邻的所有节点,并将它们全部放在“右侧” 3.)其余节点都属于二部图的“左侧” 结束试试这个:--
Bipartite.java
/*************************************************************************
*编译:javac Bipartite.java
*依赖项:Graph.java
*
*给定一个图,求(i)一个二分图或(ii)一个奇数长度的圈。
*在O(E+V)时间内运行。
*
*
*************************************************************************/
/**
*Bipartite类表示的是
*确定无向图是否为二部图或
*它有一个奇数长度的循环。
*isBipartite操作确定图形是否为
*二分体。如果是,则“颜色”操作将确定颜色
*二分法;如果不是,则oddCycle操作确定
*循环使用奇数条边。
*
*此实现使用深度优先搜索。
*构造函数所用的时间与V+E成比例
*(在最坏的情况下),
*其中V是顶点数,E是边数。
*然后,进行isbiparte和color操作
*采取固定的时间;ODD循环操作所需时间与时间成比例
*到周期的长度。
*/
公共类二部{
私有布尔值是二部的;//图是二部的吗?
private boolean[]color;//color[v]在二分的一侧给出顶点
私有布尔值[]已标记;//如果在DFS中访问了v,则标记为[v]=true
private int[]edgeTo;//edgeTo[v]=到v的路径上的最后一条边
私有堆栈循环;//奇数长度循环
/**
*确定无向图是否为二部图,并查找
*二分循环或奇长循环。
*@param G图形
*/
公共二部(图G){
isBipartite=true;
颜色=新布尔值[G.V()];
标记=新布尔值[G.V()];
edgeTo=新的整数[G.V()];
对于(int v=0;vBipartite.java
/*************************************************************************
* Compilation: javac Bipartite.java
* Dependencies: Graph.java
*
* Given a graph, find either (i) a bipartition or (ii) an odd-length cycle.
* Runs in O(E + V) time.
*
*
*************************************************************************/
/**
* The <tt>Bipartite</tt> class represents a data type for
* determining whether an undirected graph is bipartite or whether
* it has an odd-length cycle.
* The <em>isBipartite</em> operation determines whether the graph is
* bipartite. If so, the <em>color</em> operation determines a
* bipartition; if not, the <em>oddCycle</em> operation determines a
* cycle with an odd number of edges.
* <p>
* This implementation uses depth-first search.
* The constructor takes time proportional to <em>V</em> + <em>E</em>
* (in the worst case),
* where <em>V</em> is the number of vertices and <em>E</em> is the number of edges.
* Afterwards, the <em>isBipartite</em> and <em>color</em> operations
* take constant time; the <em>oddCycle</em> operation takes time proportional
* to the length of the cycle.
*/
public class Bipartite {
private boolean isBipartite; // is the graph bipartite?
private boolean[] color; // color[v] gives vertices on one side of bipartition
private boolean[] marked; // marked[v] = true if v has been visited in DFS
private int[] edgeTo; // edgeTo[v] = last edge on path to v
private Stack<Integer> cycle; // odd-length cycle
/**
* Determines whether an undirected graph is bipartite and finds either a
* bipartition or an odd-length cycle.
* @param G the graph
*/
public Bipartite(Graph G) {
isBipartite = true;
color = new boolean[G.V()];
marked = new boolean[G.V()];
edgeTo = new int[G.V()];
for (int v = 0; v < G.V(); v++) {
if (!marked[v]) {
dfs(G, v);
}
}
assert check(G);
}
private void dfs(Graph G, int v) {
marked[v] = true;
for (int w : G.adj(v)) {
// short circuit if odd-length cycle found
if (cycle != null) return;
// found uncolored vertex, so recur
if (!marked[w]) {
edgeTo[w] = v;
color[w] = !color[v];
dfs(G, w);
}
// if v-w create an odd-length cycle, find it
else if (color[w] == color[v]) {
isBipartite = false;
cycle = new Stack<Integer>();
cycle.push(w); // don't need this unless you want to include start vertex twice
for (int x = v; x != w; x = edgeTo[x]) {
cycle.push(x);
}
cycle.push(w);
}
}
}
/**
* Is the graph bipartite?
* @return <tt>true</tt> if the graph is bipartite, <tt>false</tt> otherwise
*/
public boolean isBipartite() {
return isBipartite;
}
/**
* Returns the side of the bipartite that vertex <tt>v</tt> is on.
* param v the vertex
* @return the side of the bipartition that vertex <tt>v</tt> is on; two vertices
* are in the same side of the bipartition if and only if they have the same color
* @throws UnsupportedOperationException if this method is called when the graph
* is not bipartite
*/
public boolean color(int v) {
if (!isBipartite)
throw new UnsupportedOperationException("Graph is not bipartite");
return color[v];
}
/**
* Returns an odd-length cycle if the graph is not bipartite, and
* <tt>null</tt> otherwise.
* @return an odd-length cycle (as an iterable) if the graph is not bipartite
* (and hence has an odd-length cycle), and <tt>null</tt> otherwise
*/
public Iterable<Integer> oddCycle() {
return cycle;
}
private boolean check(Graph G) {
// graph is bipartite
if (isBipartite) {
for (int v = 0; v < G.V(); v++) {
for (int w : G.adj(v)) {
if (color[v] == color[w]) {
System.err.printf("edge %d-%d with %d and %d in same side of bipartition\n", v, w, v, w);
return false;
}
}
}
}
// graph has an odd-length cycle
else {
// verify cycle
int first = -1, last = -1;
for (int v : oddCycle()) {
if (first == -1) first = v;
last = v;
}
if (first != last) {
System.err.printf("cycle begins with %d and ends with %d\n", first, last);
return false;
}
}
return true;
}
/**
* Unit tests the <tt>Bipartite</tt> data type.
*/
public static void main(String[] args) {
// create random bipartite graph with V vertices and E edges; then add F random edges
int V = Integer.parseInt(args[0]);
int E = Integer.parseInt(args[1]);
int F = Integer.parseInt(args[2]);
Graph G = new Graph(V);
int[] vertices = new int[V];
for (int i = 0; i < V; i++) vertices[i] = i;
StdRandom.shuffle(vertices);
for (int i = 0; i < E; i++) {
int v = StdRandom.uniform(V/2);
int w = StdRandom.uniform(V/2);
G.addEdge(vertices[v], vertices[V/2 + w]);
}
// add F extra edges
for (int i = 0; i < F; i++) {
int v = (int) (Math.random() * V);
int w = (int) (Math.random() * V);
G.addEdge(v, w);
}
StdOut.println(G);
Bipartite b = new Bipartite(G);
if (b.isBipartite()) {
StdOut.println("Graph is bipartite");
for (int v = 0; v < G.V(); v++) {
StdOut.println(v + ": " + b.color(v));
}
}
else {
StdOut.print("Graph has an odd-length cycle: ");
for (int x : b.oddCycle()) {
StdOut.print(x + " ");
}
StdOut.println();
}
}
}
int[,] BPGraph = new int[7,7]{
{0,1,0,1,0,0,0},
{1,0,1,0,1,1,0},
{0,1,0,1,0,0,1},
{1,0,1,0,1,1,0},
{0,1,0,1,0,0,1},
{0,1,0,1,0,0,1},
{0,0,1,0,1,1,0}
};
int[] BPArray = new int[7] { 0, 0, 0, 0, 0, 0, 0 };
public Boolean BiPartite()
{
Queue<int> VertexQueue = new Queue<int>();
int level = 0;
int nextlevel=0;
Boolean BPFlg = true;
VertexQueue.Enqueue(0);
while(VertexQueue.Count!=0)
{
int current = VertexQueue.Dequeue();
level = BPArray[current];
if (level == 0)
level = 1;
if (level == 2)
nextlevel=1;
else
nextlevel=2;
if(BPArray[current]==0)
BPArray[current] = level;
for (int i = 0; i < 7; i++)
{
if (BPGraph[current, i] == 1)
{
if (BPArray[i] == 0)
{
BPArray[i] = nextlevel;
VertexQueue.Enqueue(i);
}
else if (BPArray[i] == level)
{
BPFlg = false;
break;
}
}
}
if (!BPFlg)
break;
}
return BPFlg;
}