1.图的表示法
如果你希望通过文字性或公式性的东西将一个图中的信息完整清晰的表达出来,通常有两种办法,邻接表和邻接矩阵。这两种表示法既适用于有向图也适用于无向图。当表示一个稀疏矩阵时,我们通常采用邻接矩阵表示法,相反,对于一个稠密图,我们通常用邻接矩阵的形式来表示。
(1)邻接表
使用邻接表表示法时,我们通常将一个图记为 G=(V,E),其中V表示图中所有顶点的集合,E表示图中所有边的集合。而一个图的邻接表表示由一个包含|V|个列表的数组Adj所组成,其中每个列表与图中一个固定的顶点相对应。例如,对于一个顶点,u∈V,则列表Adj[u]包含了所有满足条件:(u,v)∈E的顶点v。每个邻接表中的顶点一般都是任意顺序存储的,当然也可以使用某种排序的方式来存储。 应用邻接表来存储图信息的一个好的特性是,它需要的存储空间小,为Θ(V+E).
邻接表稍作修改就可以表示加权图,即每条边都有着相应的权值(这些权值在某些特殊的应用场景中有着特殊的含义),权值通常由加权函数w:E—>R给出。而对于与顶点u相连的每条边对应的权值在存储的时候,可以一起存储在u的邻接表中。
当然邻接表也有其潜在的不足之处,即如果要确定图中边两点是否相邻时,唯一的方法就是遍历点的邻接表。但是这一点,正是邻接举证的优点,因此,在需要的时候可以将这两种图的表法混合使用.
(2) 邻接矩阵
在图G=(V,E)邻接矩阵表示中,首先会为图中的顶点编号:1,2,3....n,其中n=|V|,然后,就可以将图表示为n×n的矩阵。邻接矩阵表示需要占用Θ(V*V)的存储空间, 由于该邻接矩阵为一个对称型的矩阵,因此可以采用上三角形表示法,即在存储的时候进存储矩阵对角线上的元素以及对角线以上的元素,这样可以节省与一半的存储空间。
正如邻接表示法一样,邻接矩阵也可以用来表示加权的图,这时矩阵元素值得大小也就是相邻元素之间边的加权值。
2. 图的基本算法
(1)广度优先遍历
在给定图G=(V,E)和一个特定的起始节点s前提下,广度优先遍历搜索算法将搜索G中边,以期待发现可以从S到达的所有顶点,并计算出s到达所有可达顶点的距离。该算法最后还会生成一颗以s为根节点的广度优先树,树上每一个节点都为s可到达的节点。对于树上任意节点v,广度优先树中从S到V对应G中一条从S到V的一条最短路径。
该算法在搜索的过程中,始终是已发现和未发现的顶点边界,并沿其广度方向向外扩展。
㈠为了记录和跟踪该算法执行的过程,在搜索过程中为每个顶点着色:白色,灰色,黑色。
㈡算法开始时,所有的顶点为白色;随着搜索的进行,个顶点会变成灰色,最后变成黑色。
㈢在搜索中,第一次遍历到某个顶点时,该顶点置为灰色,第二次遍历这个顶点时,置位黑色。
㈣在搜索过程中,存在如下两个特性:
⑴与黑色顶点相邻的所有都是已经被遍历到的顶点(黑色或灰色)
⑵与灰色顶点相邻的所有顶点包括遍历到的和未遍历到的(灰色或白色)
具体的java执行代码:如下
㈠接口 ISearch
public interface ISearch {
public void search();
}
㈡BroadFindSearch类代码:
public class BroadFindSearch implements ISearch {
public Map<Integer,Vertex> vertexs=new HashMap<Integer,Vertex>();
public Vertex currentVertex;
public Vertex startVertex;
public BroadFindSearch(int[][] m,int len)
{
createVertexForGraph(len);
createNeighborhoodTable(len,m);
}
public void createVertexForGraph(int n)
{
for(int i=0;i<n;i++)
{
Vertex v=new Vertex(i);
vertexs.put(i, v);
}
}
public void createNeighborhoodTable(int len,int[][] m)
{
for(int i=0;i<len;i++)
{
currentVertex=vertexs.get(i);
for(int j=0;j<len;j++)
{
if(m[i][j]==1)
{
currentVertex.linkVertex.add(vertexs.get(j));
}
}
}
}
public void setStartVertex(int id)
{
this.startVertex=vertexs.get(id);
this.startVertex.distance=0;
this.startVertex.color=Color.GRAY;
}
@Override
public void search() {
// TODO Auto-generated method stub
Queue<Vertex> q=new LinkedList<Vertex>();
// PriorityQueue<Vertex> q=new PriorityQueue<Vertex>();
q.add(startVertex);
Vertex head;
while(q.peek()!=null)
{
head=q.poll();
for(Vertex v:head.linkVertex)
{
if(v.color==Color.WHITE)
{
v.color=Color.GRAY;
v.distance=head.distance+1;
v.parent=head;
q.add(v);
}
}
head.color=Color.BLACK;
}
}
public void print()
{
for(Vertex v:vertexs.values())
{
System.out.println(v);
}
}
}
㈢ 顶点类Vertex以及内部类Color
public class Vertex {
public int id;
public Color color;
public Vertex parent=null;
public int distance;
public Vector<Vertex> linkVertex;
public Vertex(int id)
{
this.id=id;
linkVertex=new Vector<Vertex>();
distance=Integer.MAX_VALUE;
color=Color.WHITE;
}
public String toString()
{
return id+":"+this.distance;
}
}
class Color{
public String color;
public Color(String c )
{
this.color=c;
}
public static final Color WHITE=new Color("white");
public static final Color GRAY=new Color("gray");
public static final Color BLACK=new Color("black");
}
㈣测试代码:
public class BFTTestCase {
private int[][] matricGraph={
{0,1,0,1,0,0,0,0},
{1,0,1,0,0,0,0,0},
{0,1,0,0,1,0,1,0},
{1,0,0,0,0,0,0,0},
{0,0,1,0,0,1,1,0},
{0,0,0,0,1,0,1,1},
{0,0,1,0,1,1,0,1},
{0,0,0,0,0,1,1,0}
};
BroadFindSearch bfs;
@Before
public void init()
{
bfs=new BroadFindSearch(matricGraph, matricGraph.length);
bfs.setStartVertex(1);
}
@Test
public void matric()
{
int count=0,n=matricGraph.length;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(matricGraph[i][j]!=0)
count++;
}
}
Assert.assertEquals(20, count);
}
@Test
public void search()
{
bfs.search();
bfs.print();
}
@After
public void destroy()
{
}
}
㈤