基本概念
在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。
在图中的数据元素通常称为顶点,V是顶点的有穷非空集合,VR是两个顶点之间的关系的集合。
有向图与无向图
若两个顶点之间的关系表示为<v, w>∈VR,称此时的图为有向图。
若<v, w>∈VR必有<w, v>∈VR,即VR是对称的,称此时的图为无向图。
如果用n表示顶点数目,e表示边或弧的数目,那么有 1/2*n*(n-1) 条边的无向图称为完全图。
具有 n* (n-1) 条弧的有向图称为有向完全图。
有时图的边或弧具有与它相关的数,这种与图的边或弧相关的数叫做权,这些权可以表示从一个顶点到另一个顶点的距离或耗费。这种带权的图通常称为网。
度
顶点v的度是和v相关联的边的数目。
对于有向图来说,以顶点v为头的弧的数目称为v的入度;以v为尾的弧的数目称为v的出度。
图的路径
无向图中从顶点v到顶点v'的路径是一个v到v'可达的关联起来的顶点序列。
第一个顶点和最后一个顶点相同的路径称为回路或环。序列中顶点不重复出现的路径称为简单路径。除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环。
连通
在无向图中,如果从顶点v到顶点v'有路径,则称v和v'是连通的。
如果对于图中的任意两个顶点都∈V,他们都是连通的,则称这个图是一个连通图。
连通分量,指的是无向图中的极大连通子图。
在有向图中,如果对于每一对顶点都∈V,他们相互之间都存在路径,则可称为强连通图。
有向图中的极大连通子图称为有向图的强连通分量。
一个连通图的生成树是一个极小连通子图,它包含有图中全部顶点,但只有足以构成一棵树的n-1条边。
如果一个有向图恰有一个顶点的入度为0,其余顶点的入度均为1,则是一颗有向树。
存储结构
数组表示法(邻接矩阵)
1 表示相连接,0 表示不相连。可以轻易知道两个顶点之间是否相连。
邻接表
只表达和顶点相连接的顶点信息,用邻接表表示图比邻接矩阵节省存储空间。在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点,但要判定任意两个顶点之间是否有边或弧相连,则需搜索该顶点所在的整个链表。
using System.Collections.Generic;
using UnityEngine.Assertions;
namespace Graph
{
public class SparseGraph
{
// 节点数
private int n;
// 边数
private int m;
// 是否为有向图
private bool directed;
// 图的具体数据
private List<int>[] g;
// 构造函数
public SparseGraph( int n , bool directed )
{
Assert.IsTrue(n >= 0);
this.n = n;
this.m = 0;
this.directed = directed;
// g初始化为n个空的vector, 表示每一个g[i]都为空, 即没有任和边
g = new List<int>[n];
for (int i = 0; i < n; i++)
g[i] = new List<int>();
}
// 返回节点个数
public int V(){ return n;}
// 返回边的个数
public int E(){ return m;}
// 向图中添加一个边
public void AddEdge(int v, int w)
{
Assert.IsTrue(v >= 0 && v < n);
Assert.IsTrue(w >= 0 && w < n);
g[v].Add(w);
if (v != w && !directed)
g[w].Add(v);
m++;
}
// 验证图中是否有从v到w的边
bool HasEdge(int v, int w)
{
Assert.IsTrue(v >= 0 && v < n);
Assert.IsTrue(w >= 0 && w < n);
for (int i = 0; i < g[v].Count; i++)
if (g[v][i] == w)
return true;
return false;
}
}
}
十字链表
可以看成是有向图的邻接表和逆邻接表结合起来得到的一种链表。
在十字链表中,容易找到以vi为头的弧,因而容易求得顶点的出度和入度(如需要,可在建立时同时求出)。
邻接多重表
在邻接表中每一条边(vi,vj)有两个结点,分别在第i个链表和第j个链表中,给这些图的操作带来不便。例如在某些图的应用中需要对边进行某种操作,如对已被搜索过的边做记号或删除一条边等,需要找到表示同一条边的两个结点。因此,这一类无向图的问题中采用邻接多重表更为合适。
对无向图而言,邻接多重表和邻接表的差别,仅仅在于同一条边在邻接表中用两个结点表示,而在邻接多重表中只有一个结点。因此,它在边结点中增加一个标识域。