1. 图的定义
图是由顶点的有穷非空集合和顶点之间边的集合组成-----由图的定义可知,一个图包括两部分信息:顶点的信息以及顶点之间关系(边或弧)的信息
2. 图的存储
2.1 邻接矩阵存储
邻接矩阵存储:也称数组表示法,其方法是用一个一维数组存储图中顶点信息,用一个二维数组存储图中边的信息(各顶点之间的邻接关系),存储顶点之间的邻接关系的二维数组称为邻接矩阵
邻接矩阵实现类:
package edu.tcu.soft;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
/*图的操作----邻接矩阵*/
public class MGraph {
private int[] vertex=new int[20]; // 存放顶点的数组
private int[][] arc=new int[20][20]; // 存放边的数组
private int vertexNum;// 存放顶点数
private int arcNum; // 存放边数
private int[] visited=new int[20]; // 是否被访问 0代表未访问、1代表已访问
// 构造函数,建立具有n个顶点e条边的图
public MGraph(T[] a, int n, int e) {
vertexNum = n;
arcNum = e;
// 分别给各顶点赋值
for (int i = 0; i < vertexNum; i++) {
vertex[i] = (Integer) a[i];
visited[i] = 0;
}
// 初始化邻接矩阵
for (int j = 0; j < vertexNum; j++)
for (int k = 0; k < vertexNum; k++)
arc[j][k] = 0;
// 依次输入每一条边
for (int r = 0; r < arcNum; r++) {
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
int j = scanner.nextInt();
arc[i][j] = 1;
arc[j][i] = 1;
}
}
// 深度遍历图
public void depthTraverse(int v) {
System.out.print(vertex[v] + " ");
visited[v] = 1; // 将该结点设置为已经被访问
for (int i = 0; i < vertexNum; i++)
// v、i两个结点之间有边,且i结点还没被访问
if (arc[v][i] == 1 && visited[i] == 0)
depthTraverse(i);
}
// 广度遍历图
public void broadthTraverse(int v) {
Queue queue = new LinkedList<>();// 队列
System.out.println(vertex[v] + " ");
visited[v] = 1; // 将该结点设置为已经被访问
queue.add(v);
// 队列不为空
while (!queue.isEmpty()) {
int ver = queue.poll();
for (int j = 0; j < vertexNum; j++)
if (arc[ver][j] == 1 && visited[j] == 0) {
System.out.println(vertex[v] + " ");
visited[j] = 1; // 将该结点设置为已经被访问
queue.add(j);
}
}
}
}
邻接矩阵测试类:
package edu.tcu.soft;
public class Test {
public static void main(String[] args) {
Integer[] a=new Integer[]{2,3,5,7};
MGraph graph=new MGraph<>(a, 4, 4);
graph.depthTraverse(3);
}
}
2.2 邻接表存储
邻接表是一种顺序存储和链接存储相结合的存储方法,类似于树的孩子链表表示法,存储边表头指针的数组和存储顶点信息的数组构成了表头数组,称为顶点表。所以在邻接表中存在两种结点结构:顶点表结点和边表结点。
顶点表实现类:
package edu.tcu.soft;
/*顶点表结点*/
public class VertexNode {
private T vertex; // 存放顶点信息
private ArcNode arcNode; // 存放边表中的第一个结点
public T getVertex() {
return vertex;
}
public void setVertex(T vertex) {
this.vertex = vertex;
}
public ArcNode getArcNode() {
return arcNode;
}
public void setArcNode(ArcNode arcNode) {
this.arcNode = arcNode;
}
public VertexNode(T vertex, ArcNode arcNode) {
super();
this.vertex = vertex;
this.arcNode = arcNode;
}
}
边表实现类:
package edu.tcu.soft;
/*边表数据结构*/
public class ArcNode {
private int adjvex; // 存放顶点表下标
private ArcNode arcNode; // 边表的下一个结点
public int getAdjvex() {
return adjvex;
}
public void setAdjvex(int adjvex) {
this.adjvex = adjvex;
}
public ArcNode getArcNode() {
return arcNode;
}
public void setArcNode(ArcNode arcNode) {
this.arcNode = arcNode;
}
}
邻接表实现类:
package edu.tcu.soft;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
/*邻接表实现类*/
public class LGraph {
@SuppressWarnings({"unchecked" })
private VertexNode[] vertexNode=new VertexNode[5]; // 顶点表数组
private int vertexNum; // 图的顶点数
private int arcNum; // 图的边数
private int[] visited=new int[4];//0代表未访问,1代表已访问
/* 构造函数,建立一个具有n个顶点e条边的图 */
@SuppressWarnings({"resource" })
public LGraph(T a[], int n, int e) {
vertexNum = n;
arcNum = e;
// 输入顶点信息,初始化顶点表
for (int i = 0; i < vertexNum; i++) {
visited[i]=0; //设置该顶点未访问
vertexNode[i]=new VertexNode(a[i], null);
}
//依次输入每一条边
for(int k=0;k queue=new LinkedList<>();
System.out.print(vertexNode[v].getVertex()+" ");
visited[v]=1;
queue.add(v);
while(!queue.isEmpty()){
int i=queue.poll();
ArcNode node=vertexNode[i].getArcNode(); //获取顶点表的第一个边表
while(node!=null){
int j=node.getAdjvex();
if(visited[j]==0){
System.out.print(vertexNode[j].getVertex()+" ");
visited[j]=1;
queue.add(j);
}
node=node.getArcNode();
}
}
}
}
测试类:
package edu.tcu.soft;
public class Test {
public static void main(String[] args) {
Integer[] a=new Integer[]{2,3,5,7};
LGraph graph2=new LGraph<>(a, 4, 4);
graph2.broadthTraverse(3);
}
}
2.3 邻接矩阵和邻接表的比较
邻接矩阵和邻接表是图的两种常用的存储结构,均可用于存储有向图和无向图,也均可用于存储网图。设图G含有n个顶点e条边,下面比较邻接矩阵和邻接表存储结构
1.空间性能比较
邻接矩阵:邻接矩阵是一个n*n的矩阵,空间代价是O(n*n)
邻接表:邻接表的空间代价与图的边数及顶点数有关,每一顶点在顶点表中都要占据一个数组元素的位置(即使该顶点没有邻接点),且每条边必须出现在某个顶点的边表中,所以当图是有向图时,邻接表的空间代价是O(n+e);当图是无线图是,邻接表的空间 代价是O(n+2*e)
哪种表示方法的存储效率高图中边的数目。邻接表仅存储实际实际出现在图中的边,而邻接矩阵则需要存储所有可能的边,但是邻接矩阵不需要结构性开销。一般情况下,图越稠密,邻接矩阵的空间效率越高,而对稀疏图(e
2.时间性能比较
邻接矩阵在图的算法中时间代价比邻接表的高,原因是:在图的算法中访问某个顶点的所有邻接点是较常见的操作。如果使用邻接表,只需要检查此顶点的边表,即只检查与它相邻的实际存在的边,平均需要查找O(e/n)次;如果使用邻接矩阵,则必须检查所有可能的边,需要查找O(n)次