图
刷题的时候,遇到图的遍历这一题,想着回忆一下深度优先遍历和广度优先遍历的知识。
图的数据结构
G(V,E) V是顶点,E是边
- n个顶点的无向完全图有 n*(n-1)/2 条边;n个顶点的有向完全图有 n*(n-1)条弧;边或弧少的图叫稀疏图,多的叫稠密图;带权重的图叫网。
- 子图:G‘的顶点和边都属于G,G’就是G的子图。
- 顶点的度:无向图就是边连接数,有向图就是入度+出度。
- 连通图:无向图中,图中任意两点之间都有路径就是连通图;极大连通子图叫连通分量(有所有顶点,是连通子图)。
- 强连通图:有向图中,图中任意一个点到另一个点之间能到就是强连通图;极大强连通子图叫强连通分量。
- 生成树:极小连通子图,有图中全部n个顶点,但只有n-1条能构成一棵树的边。
- 有向树 : 一棵树中恰有一个顶点的入度为0,而其他顶点的入度为1。
- 生成森林:一个有向图 的 若干 有向树 就叫做这个有向图的生成森林。
图的存储 - 邻接矩阵
- 邻接链表(只定义出度)逆邻接表(只定义入度)
- 十字链表 (出度入度都定义)
- 邻接多重表 (针对邻接表删除要标记的麻烦而做优化)
- 边集数组
图的遍历
深度优先遍历 DFS
从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。
深度优先遍历是使用递归的方式实现的。
// 邻接矩阵的深度优先遍历
void DFS(MGraph G, int i){
int j;
visited[i] = true;
{
// 访问操作
}
// numVertexes 顶点数,arc存储数组
for(j=0; j<G.numVertexes; ++j)
if(G.arc[i][j] == 1 && !visited[j])
DFS(G, j);
}
voidDFSTraverse(MGraph G){
int i;
for(i=0;i<G.numVertexes; ++i)
visited[i] = false;
for(i=0;i<G.numVertexes; ++i)
if(visited[i])
DFS(G,i);
}
广度优先遍历 BFS
广度优先遍历类似于数的层序遍历,从顶点v出发,访问v的未被访问的邻接点并置为已访问,记录下这些邻接点,下一次就要去访问这些邻接点的邻接点,直到所有结点被访问。
广度优先遍历我们一般使用队列来帮助实现
void BFSTraverse(MGraph G){
int i,j;
Queue Q;
for(i=0;i<G.numVertexes; ++i)
visited = false;
InitQueue(&Q);
for(i=0;i<G.numVertexes; ++i){
if(!visited[i]){
visited[i] = true;
{
// 第一个顶点的访问操作
}
EnQueue(&Q, i); // 入队
while(!isEmpty(Q)){
// 队列非空
DeQueue(&Q, i);
for(j=0;j<G.numVertexes; ++j){
if(G.arc[i][j] == 1 && !visited[j]){
visited[j] = true;
{
// 访问操作
}
EnQueue(&Q, j);
}
}
}
}
}
}