图的存储结构主要分为两种:邻接矩阵和邻接表
1.图的邻接矩阵
邻接矩阵是表示顶点之间邻接关系的矩阵。设G=(V,E)是含有n(设n>0)个顶点的图,各顶点的编号为0~n-1,则G的邻接矩阵数组A是n阶方阵。
代码如下:
/**
*
*/
package class8;
import java.lang.*;
import java.util.*;
public class MatGraphClass //图邻接矩阵类
{ final int MAXV=100; //表示最多顶点个数
final int INF=0x3f3f3f3f; //表示∞,整数的两倍不超过 0x7f7f7f7f,即int能表示的
//最大正整数。
int[][] edges; //邻接矩阵的边数组,假设元素为int类型
int n,e; //顶点数,边数
String[] vexs; //存放顶点信息
public MatGraphClass() //构造方法
{
edges=new int[MAXV][MAXV];
vexs=new String[MAXV];
}
public void CreateMatGraph(int[][] a,int n,int e) //通过边数组a、顶点数n和边数e来建立图的邻接矩阵
{
this.n=n; this.e=e; //置顶点数和边数
for (int i=0;i<n;i++)
{
edges[i]=new int[n];
for (int j=0;j<n;j++)
edges[i][j]=a[i][j];
}
}
public void DispMatGraph() //格式化输出图的邻接矩阵
{
for (int i=0;i<n;i++)
{ for (int j=0;j<n;j++)
if (edges[i][j]==INF)
System.out.printf("%4s","∞");
else
System.out.printf("%5d",edges[i][j]);
System.out.println();
}
}
public static void main(String[] args) {
MatGraphClass g=new MatGraphClass();
int n=5,e=5;
int[][] a={{0,8,g.INF,5,g.INF},{g.INF,0,3,g.INF,g.INF},
{g.INF,g.INF,0,g.INF,16},{g.INF,9,g.INF,0,g.INF},{g.INF,g.INF,g.INF,g.INF,0}};
g.CreateMatGraph(a,n,e);
g.DispMatGraph();
}
}
2.邻接表
邻接表分成两部分,左侧为一个顶点数组,右侧为表节点,核心思想为找邻居。
假设从0号顶点开始(可以从任意顶点开始,顺序不影响结果),则将0号顶点放在数组的0号位置,与0号顶点直连的有1号、3号、4号三个顶点,将之依次插入到0号右侧(1,2,3号位置可以随机插入,对结果无影响)。注意为了方便在后续算法中(如深度优先遍历,广度优先遍历)使用该存储结构,这里在链节点中存入的值是节点编号。
代码如下:
/**
*
*/
package class8;
import java.lang.*;
import java.util.*;
@SuppressWarnings("unchecked")
class ArcNode //边结点类
{ int adjvex; //该边的终点编号
ArcNode nextarc; //指向下一条边的指针
int weight; //该边的相关信息,如边的权值
}
class VNode //表头结点类型
{ String[] data; //顶点信息
ArcNode firstarc; //指向第一条边的相邻顶点
}
public class AdjGraphClass //图邻接表类
{ final int MAXV=100; //表示最多顶点个数
final int INF=0x3f3f3f3f; //表示∞
VNode[] adjlist; //邻接表头数组
int n,e; //图中顶点数n和边数e
public AdjGraphClass() //构造方法
{
adjlist=new VNode[MAXV];
for (int i=0;i<MAXV;i++)
{
adjlist[i]=new VNode();
}
}
public void CreateAdjGraph(int[][] a,int n,int e) //通过边数组a、顶点数n和边数e来建立图的邻接表
{
this.n=n; this.e=e; //置顶点数和边数
ArcNode p;
for (int i=0;i<n;i++) //检查边数组a中每个元素
{
adjlist[i].firstarc=null; //给邻接表中所有头结点的指针置初值
for (int j=n-1;j>=0;j--)
if (a[i][j]!=0 && a[i][j]!=INF) //存在一条边
{ p=new ArcNode(); //创建一个边结点p
p.adjvex=j; //存入节点编号
p.weight=a[i][j]; //存入节点权值
p.nextarc=adjlist[i].firstarc; //采用头插法插入*p
adjlist[i].firstarc=p;
}
}
}
public void DispAdjGraph() //输出图的邻接表
{
ArcNode p;
for (int i=0;i<n;i++)
{
System.out.printf(" [%d]",i);
p=adjlist[i].firstarc; //p指向第一个邻接点
while (p!=null)
{
System.out.printf("->(%d,%d)",p.adjvex,p.weight);
p=p.nextarc; //p移向下一个邻接点
}
System.out.println("->∧");
}
}
public static void main(String[] args) {
AdjGraphClass G=new AdjGraphClass();
int n=5,e=5;
int[][] a={{0,8,G.INF,5,G.INF},
{G.INF,0,3,G.INF,G.INF},
{G.INF,G.INF,0,G.INF,16},
{G.INF,G.INF,9,0,G.INF},
{G.INF,G.INF,G.INF,G.INF,0}};
G.CreateAdjGraph(a,n,e);
G.DispAdjGraph();
}
}
参考书目:
- 李春葆、李筱驰,《数据结构教程—Java语言描述》,清华大学出版社 2020年9月版