一、图概述
对图的描述有两个参数:点个数(vertex)与边数(edge)。若两节点间有边将二者相连,则称两点邻接(adjacency),点与该边成为关联(incidence)。
图又分为有向图和无向图,若一张图中每条边都具有方向,则该图为有向图 ,否则是无向图。
二、路径
1.简单路径
将每个节点均遍历一次的路径为简单路径:
2.简单环路
依次遍历每个节点并最终回到初始位置的路径为简单回路
3.欧拉环路
可经过每条边各一次的回路
4.汉密尔顿回路
可经过每个节点各一次的回路
三、图的表示方法
1.邻接矩阵
以矩阵形式表示各个顶点的连接关系。
若该图有n个节点,则生成n行n列矩阵,i行j列用0/1表示节点i与j是否有邻接关系。
2.关联矩阵
一个有n个节点与e条边组成的图可由n行e列矩阵表示。若一个节点与一条边有关联关系,则该隔填入1,否则为0。不难得出,关联矩阵中,没列有且仅有两个1。
三、实现方法
1.相邻矩阵的表示
n个n维向量组成邻接矩阵,用上述方法表示完整的图。
2.相邻顶点查找
查找相邻顶点时,只需搜索该顶点所在行中下一个‘1’所在的位置即可。
int nextNbr(int i, int j)
{
while ((-1 < j) && !exists(i, --j)); //寻找下一个相邻节点
return j; //返回该节点
}
3.边查找
判断边(i, j)是否存在
bool exists(int i, int j)
{
return (0 <= i) && (i < n) && (0 <= j) && (j < n) && E[i][j] != NULL;
}
4.边插入
在点 i, j间插入边 w
void insert(Te const & edge, int i, int j)
{
if(exists(i, j) //判断是否存在
return;
E[i][j] = new Edge<Te>(edge, w); //插入边
//更新图中原有信息
e++; //更新边数
v[i].outDegree++;
v[j].inDegree++;
}
3.边删除
该操作与边插入相似
4.顶点添加
在图中添加顶点较为麻烦,需为每个行向量增添一列,并在结尾处增加一个行向量。延长所有向量后,令新增所有边为空。
int insert(Tv const & vertex)
{
for(int j = 0; j < n; j++)
E[j].insert(NULL);
n++;
E.insert(Vector<Edge<Te>* >(n, n, NULL) );
return V.insert(Vertex<Tv>(vertex) );
}
5.顶点删除
顶点删除与新增顶点互为逆过程,代码也较为相似。需注意的是处理顶点时需注意边的关系。
四、图的遍历
最基础的图遍历方式有两种,及深度优先遍历与广度优先遍历。具体遍历方法详见博文:图的搜索