在接下来的很长一段时间里,我都将持续的学习有关图论的各类算法,学习的目标是理解并掌握基本的图论算法以及应用方式,对于此前实现过的其他数据结构均是以C++语言实现的,并且代码冗长,不时还会引出一些生涩的语法,所以为了避免这一问题,在接下来的图论算法的学习过程中我将使用此前流传甚广的Java语言来实现图论算法的各种接口,我争取里使用比较精简的代码来实现各类基础的工能,但是由于我并不是对java十分熟悉,错误之处以及疏漏在所难免,请大家谅解。实际上有关于任何算法的学习都是不关乎语言的,哪怕是用汇编语言写出一个排序算法只要能够解决实际问题那么它就是正确的并且是合理的。所谓存在即合理。那么下面给出一段十分基础并且重要的代码的实现------图的表示(基于邻接矩阵)。
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class AdjMatrix
{
private int V;//顶点
private int E;//边
private int [][] adj;//邻接矩阵
public AdjMatrix(String filename)
{//从文件中读取图的信息,并构建一个无向图
File file=new File(filename);
try(Scanner scanner=new Scanner(file))
{//这样写不用考虑回收资源
V=scanner.nextInt();//读取图的顶点数
if(V<0)
{//由于一个图最少有一个顶点,于是要考虑到方方面面的情况
throw new IllegalArgumentException("V must be non-negative");
}
adj=new int[V][V];//使用读取进来的第一行的数字创建一个二维数组
E=scanner.nextInt();//再读入图的边数
if(E<0)
{//由于一个图最少有一个顶点,于是要考虑到方方面面的情况
throw new IllegalArgumentException("E must be non-negative");
}
for(int i=0;i<E;i++)
{
//读入各个顶点的信息,顺带判断合法性
int a=scanner.nextInt();
validateVertex(a);
int b=scanner.nextInt();
validateVertex(b);
//判断是否为自环边
if(a==b)//如果某一条边的头尾节点都指向了同一个顶点,那么久认为这是一条自环边
{
throw new IllegalArgumentException("Self Loop is Detected!");
}
if(adj[a][b]==1)//如果已经有了这样的一条边,就认为他是一条平行边
{
throw new IllegalArgumentException("Parallel edges are detected!");
}
//根据各个顶点的信息,对邻接矩阵进行赋值操作
adj[a][b]=1;
adj[b][a]=1;
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
private void validateVertex(int v)
{//判断边的信息是否正确,比如:有没有某一个边的序号小于0,或者大于V
if(v<0||v>V)
{
throw new IllegalArgumentException("Vertex "+v+" is invalid");
}
}
public int V()//为用户提供接口来访问节点数以及边数
{
return V;
}
public int E()
{
return E;
}
public boolean hasEdge(int v,int w)//判断两个顶点之间是否存在一条边
{
validateVertex(v);
validateVertex(w);
return adj[v][w]==1;
}
public ArrayList<Integer> adj(int v)//返回与顶点v相邻的边
{
validateVertex(v);
ArrayList<Integer>res=new ArrayList<>();//将所有与顶点v相邻的顶点存入这个对象之中
//遍历邻接表中所有的顶点,如果顶点与v之间有一条边,那么这条边就是顶点v的一条邻边
for(int i=0;i<V;i++)
{
if(adj[v][i]==1)
{
res.add(i);//将所有的临边加入链表
}
}
return res;
}
public int degree(int v)//返回某一节点的度
{
return adj(v).size();
}
@Override
public String toString()//重写toString()方法来打印图
{
StringBuilder sb=new StringBuilder();//创建StringBuilder的对象用来操作字符串
sb.append(String.format("V = %d,E = %d\n", V,E));//首先输出有关图的信息
for(int i=0;i<V;i++)
{
for (int j=0;j<V;j++)
{
sb.append(String.format("%d ", adj[i][j]));
}
sb.append("\n");
}
return sb.toString();
}
public static void main(String []args)
{
AdjMatrix adjMatrix=new AdjMatrix("g.txt");//传入图文件,并创建一个图
System.out.println(adjMatrix);
}
}
也许你已经注意到了这里对于一张图的初始化工作是基于文件来实现的,与此前使用C++实现的其他的算法不同,图论中的算法的输入往往需要涉及大量的边抑或是顶点,如果使用控制台来进行数据的导入那么势必会带来麻烦,所以这里一律采用文件的形式读入数据。这里使用的文件一般是一个txt文本文件。这段代码中所提及的g.txt的内容放在下面,如果你需要执行上述代码,那么请将下面的文本内容组织成为一个文本文档并且放入与本文件同一级目录下便可正确执行,此后不再提及有关于此的问题,直接附以文本文件的内容。
7 7
0 1
0 2
1 3
1 4
2 3
2 6
5 6