JAVA数据结构与算法之————图(邻接矩阵)
本文将介绍图的存储结构:邻接矩阵的构造,图的深度优先遍历,图的广度优先遍历
图的结构:
public class MGraph {
/*
* 存储图中节点的数组
* */
private String[] vexs;
/*
* 邻接矩阵
* */
private int[][] arc;
/*节点数量和边数*/
private int numVertexes, numEdgs;
/*记录节点是否被访问的数组*/
private boolean[] isVisited;
MGraph(){
/*初始化isVisited*/
isVisited = new boolean[10];
for(int i = 0; i < 10; i++){
isVisited[i] = false;
}
}
MGraph(String[] v, int[][] a, int numV, int numE){
this.vexs = v;
this.arc = a;
this.numVertexes = numV;
this.numEdgs = numE;
isVisited = new boolean[numVertexes];
for(int i = 0; i < isVisited.length; i++){
isVisited[i] = false;
}
}
public String[] getVexs(){
return this.vexs;
}
public int[][] getArc(){
return arc;
}
public int getNumVertexes(){
return this.numVertexes;
}
public int getNumEdgs(){
return this.numEdgs;
}
public void setVexs(String[] v){
this.vexs = v;
}
public void setArc(int[][] a){
this.arc = a;
}
public void setNumVertexes(int numV){
this.numVertexes = numV;
}
public void setNumEdgs(int numE){
this.numEdgs = numE;
}
public void initialIsVisited(){
this.isVisited = new boolean[this.numVertexes];
for(int i = 0; i < isVisited.length; i++){
isVisited[i] = false;
}
}
public boolean[] getIsVisited(){
return this.isVisited;
}
public void setIsVisited(boolean[] b){
this.isVisited = b;
}
}
创建图
为了方便,构造图的数据从文件中读取文件data.txt如下:
9
15
v0
v1
v2
v3
v4
v5
v6
v7
v8
0 1 1
0 2 5
1 2 3
1 3 7
1 4 5
2 4 1
2 5 7
3 4 2
3 6 3
4 5 3
4 6 6
4 7 9
5 7 5
6 7 2
6 8 7
7 8 4
/*
* MGraph 是图结构
* isDigraph 判断构建的是否是有向图
* */
public void createMGraph(MGraph G, boolean isDigraph) throws IOException{
/*
* 读取文件数据
* */
try(BufferedReader br = new BufferedReader(new FileReader("./src/graph/dataMG.txt"))){
System.out.println("输入顶点数和边数");
G.setNumVertexes(Integer.parseInt(br.readLine()));
G.setNumEdgs(Integer.parseInt(br.readLine()));
String[] vexs = new String[G.getNumVertexes()];
int[][] arc = new int[G.getNumVertexes()][G.getNumVertexes()];
System.out.println("输入结点信息,建立结点表");
for (int i = 0; i < G.getNumVertexes(); i++) {
vexs[i] = br.readLine();
}
G.setVexs(vexs);
System.out.println("读入边信息,建立邻接矩阵");
/*
* 初始化arc
* */
for (int i = 0; i < G.getNumVertexes(); i++) {
for (int j = 0; j < G.getNumVertexes(); j++) {
if (i == j) {
arc[i][j] = 0;
} else {
arc[i][j] = 99999;
}
}
}
/*
* 读入数据,构建arc
* */
for (int k = 0; k < G.getNumEdgs(); k++) {
System.out.printf("读入边%d的上标i,小标j, 和权重w\n", k + 1);
String[] inputs = br.readLine().trim().split(" ");
arc[Integer.parseInt(inputs[0])][Integer.parseInt(inputs[1])] = Integer.parseInt(inputs[2]);
/*
* 如果是无向图,则arc[i][j] 和 arc[j][i] 设置相同的值
* */
if (!isDigraph) {
arc[Integer.parseInt(inputs[1])][Integer.parseInt(inputs[0])] = Integer.parseInt(inputs[2]);
}
}
G.setArc(arc);
}catch (FileNotFoundException e){
e.printStackTrace();
}
}
图的深度优先遍历
/*
* 图的深度优先遍历,非联通图也适用
* */
public void DFSTraverse(MGraph MG) {
for (int i = 0; i < MG.getNumVertexes(); i++) {
if (MG.getIsVisited()[i] == false) {
DFSWithMGraph(MG, i);
}
}
}
/*
* 从节点i进行递归深度优先遍历,如果是联通无向图这个方法就可以得到正确结果
* 但是有向图或者非联通图还需结合方法DFSTraverse才能得到正确结果
* */
public void DFSWithMGraph(MGraph MG, int i) {
MG.getIsVisited()[i] = true;
System.out.println(MG.getVexs()[i]);
for (int j = 0; j < MG.getNumVertexes(); j++) {
if (MG.getArc()[i][j] != 99999 && MG.getIsVisited()[j] == false) {
DFSWithMGraph(MG, j);
}
}
}
图的广度优先遍历
/*
* 图的广度优先遍历
* */
public void BFSTraverse(MGraph G){
/*队列记录图广度优先遍历节点的顺序*/
ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
/*初始化isVisited数组*/
G.initialIsVisited();
/*将第一个节点元素进队*/
queue.add(0);
/*标记第一个节点为已访问*/
G.getIsVisited()[0] = true;
System.out.println(G.getVexs()[0]);
/*遍历队列*/
while(!queue.isEmpty()){
/*出队,然后将节点temp相连的节点依次进队*/
int temp = queue.poll();
for(int j = 0; j < G.getNumVertexes(); j++){
if(G.getIsVisited()[j] == false && G.getArc()[temp][j] == 1){
queue.add(j);
G.getIsVisited()[j] = true;
System.out.println(G.getVexs()[j]);
}
}
}
}
我将在下一篇博客中介绍图的另一种存储结构 邻接表,和图邻接表结构图的建立, 图的深度优先遍历,广度优先遍历等操作,有需要的同学可以前往指教。