图的存储结构
图的存储结构比较复杂,其复杂性主要表现在:
◆任意顶点之间可能存在联系,无法以数据元素在存储区中的物理位置来表示元素之间的关系。
◆图中顶点的度不一样,有的可能相差很大,若按度数最大的顶点设计结构,则会浪费很多存储单元,反之按每个顶点自己的度设计不同的结构,又会影响操作。
图的常用的存储结构有:邻接矩阵、邻接链表、十字链表、邻接多重表和边表,其中邻接矩阵和邻接链表是比较常用的表示方法。
邻接矩阵(数组)表示法
基本思想:对于有n个顶点的图,用一维数组vexs[n]存储顶点信息,用二维数组A[n][n]存储顶点之间关系的信息。该二维数组称为邻接矩阵。在邻接矩阵中,以顶点在vexs数组中的下标代表顶点,邻接矩阵中的元素A[i][j]存放的是顶点i到顶点j之间关系的信息。
1无向图的数组表示
(1)无权图的邻接矩阵
无向无权图G=(V,E)有n(n≧1)个顶点,其邻接矩阵是n阶对称方阵,如下图所示。其元素的定义如下:
(2)带权图的邻接矩阵
无向带权图G=(V,E)的邻接矩阵如下图所示。其元素的定义如下:
(3)无向图邻接矩阵的特性
◆邻接矩阵是对称方阵;
◆对于顶点vi,其度数是第i行的非0元素的个数;
◆无向图的边数是上(或下)三角形矩阵中非0元素个数。
2有向图的数组表示
(1)无权图的邻接矩阵
若有向无权图G=(V,E)有n(n≧1)个顶点,则其邻接矩阵是n阶对称方阵,如图7-7所示。元素定义如下:
(2)带权图的邻接矩阵
有向带权图G=(V,E)的邻接矩阵如图所示。其元素的定义如下:
⑶有向图邻接矩阵的特性
◆对于顶点vi,第i行的非0元素的个数是其出度OD(vi);第i列的非0元素的个数是其入度ID(vi)。
◆邻接矩阵中非0元素的个数就是图的弧的数目。
邻接矩阵表示法
上一节讲了图的定义和基本概念,以及接口的定义,现在对上一节中的接口进行类的实现,如下。
MatrixEdge.java
package datastructure.graph;
/**
* 邻接矩阵表示法表示的图
* @author luoweifu
*
*/
public class MatrixEdge extends Edge {
private Object v1, v2;
/**
* 构造函数
* @param weight 权值
*/
public MatrixEdge(double weight) {
v1 = null;
v2 = null;
this.info = null;
this.weight = weight;
}
/**
* 构造函数
* @param v1 第一个顶点
* @param v2 第二个顶点
* @param info 边的信息
* @param weight 权值
*/
public MatrixEdge( Object v1, Object v2, Object info, double weight ) {
super(info, weight);
this.v1 = v1;
this.v2 = v2;
}
@Override
public Object getFirstVertex() {
return v1;
}
@Override
public Object getSecondVertex() {
return v2;
}
@Override
public int compareTo(Object o) {
Edge e = (Edge)o;
if(this.weight > e.getWeight())
return 1;
else if(this.weight < e.getWeight())
return -1;
else
return 0;
}
@Override
public boolean equals(Object obj) {
return ((Edge)obj).info.equals(info) && ((Edge)obj).getWeight() == this.weight;
}
@Override
public String toString() {
//return "边信息:" + info + "\t权值:" + weight + "\t顶点1:" + getFirstVertex() + "\t顶点2:" + getSecondVertex();
return "" + weight;
}
}
MatrixGraph.java
package datastructure.graph;
import datastructure.list.ArrayList;
import datastructure.list.List;
import datastructure.queue.ArrayQueue;
import datastructure.queue.Queue;
/**
* 邻接矩阵法表示图
* @author luoweifu
*
*/
public class MatrixGraph implements Graph {
private static final int defaultSize = 10;
private int maxLen; //矩阵的最大长度
private int edgeNum; //边的条数
private List vertexs;
private Edge edges[][];
private enum Visit{unvisited, visited};
/**
* 构造函数
*/
public MatrixGraph() {
maxLen = defaultSize;
vertexs = new ArrayList();
edges = new MatrixEdge[maxLen][maxLen];
}
/**
* 构造函数
* @param vexs 顶点的数组
*/
public MatrixGraph(Object vexs[]) {
maxLen = vexs.length;
vertexs = new ArrayList();
edges = new MatrixEdge[maxLen][maxLen];
for(int i=0; i<maxLen; i++) {
vertexs.add(vexs[i]);
}
}
@Override
public void addEdge(Object v1, Object v2, double weight) {
int i1 = vertexs.indexOf(v1);
int i2 = vertexs.indexOf(v2);
//System.out.println("i1: " + i1 + " i2:" + i2);
if(i1>=0 && i1<vertexs.size() && i2 >=0 && i2<vertexs.size()) {
edges[i1][i2] = new MatrixEdge(v1, v2, null, weight);
edgeNum ++;
} else {
throw new ArrayIndexOutOfBoundsException("顶点越界或对应的边不合法!");
}
}
@Override
public void addEdge(Object v1, Object v2, Object info, double weight) {
int i1 = vertexs.indexOf(v1);
int i2 = vertexs.indexOf(v2);
if(i1>=0 && i1<vertexs.size() && i2 >=0 && i2<vertexs.size()) {
edges[i1][i2] = new MatrixEdge( v1, v2, info, weight);
edgeNum ++;
} else {
throw new ArrayIndexOutOfBoundsException("顶点越界或对应的边不合法!");
}
}
@Override
public void addVex(Object v) {
vertexs.add(v);
if(vertexs.size() > maxLen) {
expand();
}
}
private void expand() {
MatrixEdge newEdges[][] = new MatrixEdge[2*maxLen][2*maxLen];
for(int i=0; i<maxLen; i++) {
for(int j=0; j<maxLen; j++) {
newEdges[i][j] = (MatrixEdge) edges[i][j];
}
}
edges = newEdges;
}
@Override
public int getEdgeSize() {
return edgeNum;
}
@Override
public int getVertexSize() {
return vertexs.size();
}
@Override
public void removeEdge(Object v1, Object v2) {
int i1 = vertexs.indexOf(v1);
int i2 = vertexs.indexOf(v2);
if(i1>=0 && i1<vertexs.size() && i2 >=0 && i2<vertexs.size()) {
if(edges[i1][i2] == null) {
try {
throw new Exception("该边不存在!");
} catch (Exception e) {
e.printStackTrace();
}
} else {
edges[i1][i2] = null;
edgeNum --;
}
} else {
throw new ArrayIndexOutOfBoundsException("顶点越界或对应的边不合法!");
}
}
@Override
public void removeVex(Object v) {
int index = vertexs.indexOf(v);
int n = vertexs.size();
vertexs.remove(index);
for(int i=0; i<n; i++){
edges[i][n-1] = null;
edges[n-1][i] = null;
}
}
@Override
public String printGraph() {
StringBuilder sb = new StringBuilder();
int n = getVertexSize();
for (int i = 0; i < n; i++) {
for(int j=0; j<n; j++) {
sb.append(" " + edges[i][j]);
}
sb.append("\n");
}
return sb.toString();
}
@Override
public void clear() {
maxLen = defaultSize;
vertexs.clear();
edges = null;
}
@Override
public String bfs(Object o) {
Visit visit[] = new Visit[vertexs.size()];
for(int i=0; i<vertexs.size(); i++)
visit[i] = Visit.unvisited;
StringBuilder sb = new StringBuilder();
bfs(o, visit, sb);
return sb.toString();
}
private void bfs(Object o, Visit[] visit, StringBuilder sb) {
Queue queue = new ArrayQueue();
int n = vertexs.indexOf(o);
sb.append(o + "\t");
visit[n] = Visit.visited;
queue.push(o);
while(!queue.isEmpty()) {
Object u = queue.deQueue();
Object v = getFirstVertex(u);
while(null != v) {
if(Visit.unvisited == visit[vertexs.indexOf(v)]) {
sb.append(v + "\t");
visit[vertexs.indexOf(v)] = Visit.visited;
queue.push(v);
}
v = getNextVertex(u, v);
}
}
}
@Override
public String dfs(Object o) {
Visit visit[] = new Visit[vertexs.size()];
for(int i=0; i<vertexs.size(); i++)
visit[i] = Visit.unvisited;
StringBuilder sb = new StringBuilder();
dfs(o, visit, sb);
return sb.toString();
}
private void dfs(Object o, Visit[] visit, StringBuilder sb) {
int n = vertexs.indexOf(o);
sb.append(o + "\t");
visit[n] = Visit.visited;
Object v = getFirstVertex(o);
while(null != v) {
if(Visit.unvisited == visit[vertexs.indexOf(v)])
dfs(v, visit, sb);
v = getNextVertex(o, v);
}
}
@Override
public Object getFirstVertex(Object v) {
int i = vertexs.indexOf(v);
if(i<0)
throw new ArrayIndexOutOfBoundsException("顶点v不存在!");
for(int col=0; col<vertexs.size(); col++)
if(edges[i][col] != null)
return vertexs.get(col);
return null;
}
@Override
public Object getNextVertex(Object v1, Object v2) {
int i1 = vertexs.indexOf(v1);
int i2 = vertexs.indexOf(v2);
if(i1<0 || i2<0)
throw new ArrayIndexOutOfBoundsException("顶点v不存在!");
for(int col=i2+1; col<vertexs.size(); col++)
if(edges[i1][col] != null)
return vertexs.get(col);
return null;
}
}
测试程序Test.java
package datastructure.graph;
public class Test {
public static void main(String args[]) {
Object obj[] = { 'A', 'B', 'C', 'D', 'E', 'F' };
//Graph graph = new MatrixGraph(obj);
Graph graph = new MatrixGraph(obj);
//graph.addVex('F');
graph.addEdge('A','C',5);
graph.addEdge('B','A',2);
graph.addEdge('C','B',15);
graph.addEdge('E','D',4);
graph.addEdge('F','E',18);
graph.addEdge('A', 'F', 60);
graph.addEdge('C', 'F', 70);
System.out.println(graph.printGraph());
/*graph.removeEdge('A', 'C');
System.out.println(graph.printGraph());
graph.removeVex('E');
System.out.println(graph.printGraph());*/
System.out.println(graph.dfs('A'));
System.out.println(graph.bfs('A'));
}
}
分享到:
相关推荐
根据给定文件的信息,我们可以总结出以下关于“数据结构源代码——邻接矩阵”的相关知识点: ### 一、邻接矩阵的基本概念 邻接矩阵是一种用于表示图的数学表示方式,其中图由顶点集V和边集E组成。对于一个具有n个...
#### 邻接矩阵表示法 在图的表示方法中,邻接矩阵是一种简单直观的方法,适用于稠密图(即边的数量接近于顶点数量的平方)。邻接矩阵是一个二维数组,对于无向图而言,数组中的元素\[A\_{ij}\]表示第\(i\)个顶点到...
Graphm.h则可能扩展了GraphBase,具体实现了邻接矩阵表示法。主程序main.cpp可能会包含一系列测试用例,用于验证所实现的图操作是否正确。 在main.cpp中,学生可能需要创建图对象,然后利用邻接矩阵进行各种操作,...
相比其他表示方法,如邻接矩阵,邻接表通常更适合表示稀疏图,并且能够更高效地进行遍历操作。 在本例中,邻接表通过以下结构定义: - `struct ArcNode`:表示一条边的信息,包含指向目标顶点的指针 `adjvex` 和...
- **邻接矩阵**:表示顶点之间边的存在与否的一种矩阵表示方式,对于无向图来说,邻接矩阵是对称的;对于有向图,则不一定是对称的。 - **置换相似**:两个矩阵如果可以通过有限次的行(列)交换而使得一个矩阵变为...
### 邻接矩阵表示法 邻接矩阵是一种用于表示图的数据结构,它通过一个二维数组(或矩阵)来表示图中各顶点之间的连接关系。对于无向图来说,如果顶点\( i \)和顶点\( j \)之间有一条边,则邻接矩阵\( G[i][j] \)和\...
以上就是关于“数据结构-图的相关代码”所涉及的知识点,包括图的两种常见表示法——数组表示法和邻接表表示法,以及有向图的邻接矩阵表示法和图的两种遍历方法。这些概念在解决实际问题,如网络路由、社交网络分析...
图的表示和实现是数据结构课程中的重要内容,而邻接矩阵表示法和邻接表表示法是实现图结构的两种常见方法。 邻接矩阵表示法使用一个二维数组来存储图的信息,其中数组的每一个元素表示对应顶点之间的边的有无,即...
### 二、邻接矩阵表示法 邻接矩阵是表示图的一种常用方法,它用一个二维数组来表示图中的顶点之间的连接关系。对于一个含有N个顶点的图,它的邻接矩阵是一个N×N的矩阵,其中元素`arcs[i][j]`表示顶点i到顶点j的边...
在邻接矩阵表示法中,图的创建过程包括以下步骤: - 首先,通过键盘输入顶点的数量和弧的数量。 - 然后,初始化一个大小为顶点数量的矩阵,所有元素初始化为0,表示没有边连接。 - 接着,输入每条弧的信息,包括...
《Dijkstra最短路径算法详解——邻接矩阵结构在C++中的实现》 Dijkstra算法是一种经典的图论算法,主要用于寻找图中从一个指定顶点到其他所有顶点的最短路径。它由荷兰计算机科学家艾兹格·迪科斯彻在1956年提出,...
本文将深入探讨哈工大数据结构作业中图结构的相关内容,包括图的两种主要表示方法——邻接矩阵和邻接表,以及图的转换算法和深度遍历算法。 首先,图由顶点(节点)和边组成,顶点之间可以存在连接关系。图的表示...
- 邻接矩阵表示法使用一个一维数组存储图的顶点信息,用二维矩阵存储图中顶点之间的关系。 - 邻接表表示法使用链式存储结构,对图中每个顶点建立一个单链表,单链表中的结点表示依附于该顶点的边。 ##### 2. 图的...
2.1.1 邻接矩阵表示法 在本系统中,采用邻接矩阵来存储图的信息,即用二维数组表示景点之间的连接关系,数组元素非零值表示两个景点之间有直接的连接,值的大小表示连接的权重或距离。 2.1.2 邻接矩阵 邻接矩阵是一...
C++中实现地图着色问题,我们可以使用邻接矩阵或邻接表来表示图。邻接矩阵是一个二维数组,用于存储图中节点之间的连接信息;而邻接表则是通过链表或者向量来表示节点的邻居,更节省空间。 1. **邻接矩阵**:对于每...
根据给定的信息,本文将详细解释“数据结构——图的遍历”,重点在于图的邻接矩阵表示法、图的不同类型及其定义与初始化过程。 ### 图的定义 图是一种非线性的数据结构,由顶点集V和边集E组成,记为G=(V,E)。其中V...
例如,邻接矩阵可以转化为邻接表,以提高遍历效率。 接下来,我们将重点讨论最短路径求法。在图中寻找从一个顶点到另一个顶点的最短路径是常见的问题,例如在地图导航中寻找最短路线。C#中,常用的最短路径算法有:...
1. **程序控制流图 (Control Flow Graph, CFG)**:程序控制流图是一种图形表示法,用于描述程序执行时可能的控制流程。在本题中,你需要根据描述中的程序流程图来绘制对应的控制流图。一个基本的控制流图由节点...
在这个任务中,学生需要使用数据结构,特别是有向图的邻接矩阵表示法,来实现狄克斯特拉算法。 狄克斯特拉算法是一种用于寻找图中从特定源节点到其他所有节点的最短路径的算法,特别适用于有权值的有向图。它的基本...