您的位置:首页 > 编程语言 > Java开发

c2java 第6篇 图的表示,最短路,圈检测和拓扑排序

2014-04-21 19:54 369 查看
/*

图的表示

===

最简单的是临接矩阵了

int n = 10;

int[][] adjMat = new int

;

如果边数接近顶点数的平方,就用这个很合适。

如果边比较稀疏,顶点又比较多,为了不浪费空间,可选用临接表

int i, n = 10;

int[][] adjList = new int
[0];

for(i = 0; i < adjList.length; ++i){

adjList[i] = new int[i+1];

}

这种表示有个优点是查询一个顶点的所有临接顶点很高效,并且和C比较,

我们不需要单独记录每个数组的长度。



上面两种写法是为了便于移植到C。如果图顶点或边发生变化,纵向和横向的组合可以用:

Vector, ArrayList, LinkedList. 最动态的是LinkedList+LinkedList.

如果图需要动态的增加删除顶点和边,则用链接表比较合适。

通常情况下,比如oj,图建好了之后不会变化,因此下面的代码采用第二种写法。

但是如果给的是点对,需要两遍扫描,对于stdin是不行的。另外,表采用数组还是链接引用的形式,

表面上看,构造图时数组来回复制效率低下,但是以后的访问因为cache局部性变得高效。

属性表示

====

顶点的附加属性,可以开数组int attr
表示;

边的附加属性比如权重,必须Edge
了。对于一些需要直接attr(u,v)的,attr

更简单。

图的遍历

====

dfs可用来判断一个图是不是有向无环图,做拓扑排序。

传统教科书上拓扑排序一般是从入度为零的顶点开始的,基于dfs则不必要。

问题1:拓扑排序结果不唯一,对于oj来说,如何判定一个结果是对的?

回答:检查图的每条边是否和这个结果是否相容。

问题2:第一次测试时因为没有加颜色判断,导致jvm栈不够。jvm 默认的栈空间有多大?

回答:-Xss默认每个线程栈是1M [1]

问题3:手动模拟栈与递归的写法,谁好谁坏?

bfs 可用来找最短路,这里假定直接相邻的两个顶点的距离是1。具体做法:

在把相邻顶点入队列前,记录他的父顶点。

关于队列,我们容知道最大为顶点个数n, 但是基于数组必然要循环利用空间,手写麻烦,于是采用标准库的LinkedList。

关于距离1的假设,在一个1日常活动的区域内,比如坐公交,似乎是合理的。这里隐含的是假设一个区域内是均衡的。

Ref

[1] http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html http://stackoverflow.com/questions/17090778/optimization-on-algorithm-to-check-whether-for-a-given-directed-graph-there-is
*/

import java.io.*;

import java.util.*;

public class Graph

{

int n, m; /*顶点数,边数*/

int[][] adjList;

int[] edgeCnt, edgeCap;

byte[] color; /*for dfs: 0--white, 1--gray, 2--black*/

int initGraph(int vertexNum, int edgeNum)

{

int i;

n = vertexNum; m = edgeNum;

adjList = new int
[0];

edgeCnt = new int
;

edgeCap = new int
;

for(i = 0; i < n; ++i){

edgeCnt[i] = 0;

edgeCap[i] = 10;

adjList[i] = new int[edgeCap[i]];

}

color = new byte
;

return 0;

}

void trimToSize()

{

int i;

for(i = 0; i < n; ++i){

adjList[i] = Arrays.copyOf(adjList[i], edgeCnt[i]);

}

edgeCnt = null; edgeCap = null;

}

int addEdge(int v, int w)

{

if(edgeCnt[v] >= edgeCap[v]){

int newCap = edgeCap[v] + 10;

adjList[v] = Arrays.copyOf(adjList[v], newCap);

edgeCap[v] = newCap;

}

adjList[v][edgeCnt[v]++] = w;

return 0;

}

int[] getNeighbors(int v)

{

return adjList[v];

}

int buildGraph() throws IOException

{/*return 0 if ok*/

/*假设输入顶点数,边数,之后是m对边(v,w)*/

int i, n, m, v, w;

Scanner in = new Scanner(System.in);

n = in.nextInt();

m = in.nextInt();

if((n < 1) || (m < 1)){return -1;}

initGraph(n, m);

for(i = 0; i < m; ++i){

v = in.nextInt(); // - 1;

w = in.nextInt(); // - 1;

addEdge(v, w);

}

trimToSize();

return 0;

}

void dfs(int v, StringBuffer out)

{

int i, w = 0;

int[] nei = getNeighbors(v);

color[v] = 1;

for(i = 0; i < nei.length; ++i){

w = nei[i];

if(0 == color[w])dfs(w, out);

else if(1 == color[w]){/*a cycle is found.*/}

}

color[w] = 2;

out.insert(0, ',');

out.insert(0, v);

//System.out.printf("v = %d out = %s %n", v, out);

}

void topoSort(StringBuffer out )

{

int i;

out.delete(0, out.length());

Arrays.fill(color, (byte)0);

for(i = 0; i < n; ++i){

if(0 == color[i])dfs(i, out);

}

}

void bfs(int v, StringBuffer out)

{

int i, w;

int[] nei;

LinkedList<Integer> qu = new LinkedList<Integer>();

out.delete(0, out.length());

Arrays.fill(color, (byte)0);

qu.push(v);

while(!qu.isEmpty()){

v = qu.pop();

out.append(v);

out.append(',');

color[v] = 1; /*visited*/

nei = getNeighbors(v);

for(i = 0; i < nei.length; ++i){

w = nei[i];

if(0 == color[w])qu.push(w);

}

}

}

public static void main (String[] arg) throws IOException

{

StringBuffer out = new StringBuffer("");

Graph g = new Graph();

g.buildGraph();

g.dfs(0, out);

System.out.println("dfs: " + out);

g.bfs(0, out);

System.out.println("bfs: " + out);

g.topoSort(out);

System.out.println("topoSort: " + out);

}

}

/*

$ cat in.txt

9 9

0 1 0 3

1 2

2 3

5 6 5 8

6 3 6 7

8 7

6 7

0 1 0 2

1 3

3 4

4 1 4 5

5 2

ludi@ubun:~/java

$ javac -g Graph.java && cat in.txt | java Graph

dfs: 0,1,2,3,

bfs: 0,3,1,2,

topoSort: 5,8,6,7,4,0,1,2,3,

ludi@ubun:~/java

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: