图的存储结构
前言
一个图就是一些顶点的集合,这些顶点通过一系列边结对(连接)。顶点用圆圈表示,边就是这些圆圈之间的连线。顶点之间通过边连接。图的存储结构常用的有两种,邻接矩阵和邻接表
一、邻接矩阵
设图G有n 个顶点,则邻接矩阵是一个n阶方阵。
当矩阵中的 [i,j] !=0(下标从1开始) ,代表其对应的第i个顶点与第j个顶点是连接的。
- 无向图的邻接矩阵是对称矩阵。
- 有向图的邻接矩阵不一定对称。
定义的图的结构如下:
struct VertexType
{
public int no;
public string data;
}
struct MGraph
{
public int[,] edges;
public int n, e;
public VertexType[] vexs;
}
//------图的邻接表---------------------------------------------------
class ArcNode
{
public int adjvex;
public ArcNode nextarc;
public int weight;
}
struct VNode
{
public string data;
public ArcNode firstarc;
}
struct ALGraph
{
public VNode[] adjlist;
public int n, e;
}
class GraphClass
{
const int MAXV = 100; //最大顶点个数
const int INF = 32767; //用INF表示∞
int flag = 0;
public MGraph g = new MGraph();
public ALGraph G = new ALGraph();
public GraphClass() //构造函数
{
g.edges = new int[MAXV, MAXV];
g.vexs = new VertexType[MAXV];
G.adjlist = new VNode[MAXV];
}
}
图的邻接矩阵存储的代码如下:
public void CreateMGraph(int n, int e, int[,] a) //通过相关数据建立邻接矩阵
{
int i, j;
g.n = n;
g.e = e;
for (i = 0; i < g.n; i++)
{
for (j = 0; j < g.n; j++)
{
g.edges[i, j] = a[i, j];
}
}
for (i = 0; i < g.n; i++)
{
int t = 0;
for (j = 0; j < g.n; j++)
{
if(a[i,j]==1)
{
t++;
}
}
if(t==0)
{
flag = 1;
break;
}
}
}
public string DispMGraph() //输出图的邻接矩阵
{
string mystr = "";
int i, j;
for (i = 0; i < g.n; i++)
{
for (j = 0; j < g.n; j++)
if (g.edges[i, j] == INF)
mystr += string.Format("{0,-3}", "∞");
else
mystr += string.Format("{0,-4}", g.edges[i, j].ToString());
mystr += "\r\n";
}
return mystr;
}
二、邻接表
为图G中的每一个顶点建立一个单链表,每条链表的结点元素为与该顶点连接的顶点。
图的邻接表存储的代码如下:
public void MatToList() //将邻接矩阵g转换成邻接表G
{
int i, j;
ArcNode p;
for (i = 0; i < g.n; i++) //给邻接表中所有头结点的指针域置初值
G.adjlist[i].firstarc = null;
for (i = 0; i < g.n; i++) //检查邻接矩阵中每个元素
for (j = g.n - 1; j >= 0; j--)
if (g.edges[i, j] != 0 && g.edges[i, j] != INF) //存在一条边
{
p = new ArcNode(); //创建一个结点p
p.adjvex = j;
p.weight = g.edges[i, j]; //边的权值
p.nextarc = G.adjlist[i].firstarc; //采用头插法插入p
G.adjlist[i].firstarc = p;
}
G.n = g.n;
G.e = g.e;
}
public string DispALGraph() //输出图的邻接表
{
string mystr = "";
int i;
ArcNode p;
for (i = 0; i < G.n; i++)
{
mystr += "[" + i.ToString() + "]";
p = G.adjlist[i].firstarc; //p指向第一个邻接点
if (p != null)
mystr += " →";
while (p != null)
{
mystr += " " + p.adjvex.ToString() + "(" + p.weight.ToString() + ")";
p = p.nextarc; //p移向下一个邻接点
}
mystr += "\r\n";
}
return mystr;
}
总结
在边比较少的情况下,用邻接表比邻接矩阵更节省空间,在邻接表中更容易找到第一个邻接点和下一个邻接点,判断两点是否有边更加的方便,邻接表更加适合于无向图。