求连通图的所有深度优先遍历序列
在图论中,连通图基于连通的概念。在一个无向图G 中,若从顶点vi到顶点vj有路径相连(当然从vj到vi也一定有路径),则称vi和vj是连通的。如果 G 是有向图,那么连接vi和vj的路径中所有的边都必须同向。如果图中任意两点都是连通的,那么图被称作连通图。如果此图是有向图,则称为强连通图(注意:需要双向都有路径)。图的连通性是图的基本性质。
图1-连通图
连通分量:无向图G的一个极大连通子图称为G的一个连通分量(或连通分支)。连通图只有一个连通分量,即其自身;非连通的无向图有多个连通分量。
强连通图:有向图G=(V,E) 中,若对于V中任意两个不同的顶点 x和 y,都存在从x到 y以及从 y到 x的路径,则称 G是强连通图。相应地有强连通分量的概念。强连通图只有一个强连通分量,即是其自身;非强连通的有向图有多个强连分量。
单向连通图:设G=<V,E>是有向图,如果u->v意味着图G至多包含一条从u到v的简单路径,则图G为单连通图。
弱连通图:将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。
/**
* 实验题目:
* 求连通图的所有深度优先遍历序列
* 实验目的:
* 领会图的深度优先遍历算法
* 实验内容:
* 编写程序,假设一个连通图采用邻接表存储,输出它的所有深度优先
* 遍历序列。
*/
#include <stdio.h>
#include <malloc.h>
#define INF 32767 //定义∞
#define MAXV 100 //最大顶点个数
typedef char InfoType;
/*-------------------------以下定义邻接矩阵类型---------------------------*/
typedef struct
{
int no; //顶点编号
InfoType info; //顶点信息
}VertexType; //顶点类型
typedef struct
{
int edges[MAXV][MAXV]; //邻接矩阵数组(用一个二维数组存放顶点间关系(边或弧)的数据)
int n; //顶点数
int e; //边数
VertexType vexs[MAXV]; //存放顶点信息(用一个一维数组存放图中所有顶点数据)
}MatGraph; //完整的图邻接矩阵类型
//邻接表表示法-将每个顶点的邻接点串成一个单链表
/*-----------以下定义邻接表类型--------------*/
typedef struct ArcNode
{
int adjvex; //该边的邻接点编号
struct ArcNode *nextarc; //指向下一条边的指针
int weight; //该边的相关信息,如权值(用整型表示)
}ArcNode; //边结点类型
typedef struct VNode
{
InfoType info; //顶点其他信息
int cnt; //存放顶点入度,仅用于拓扑排序
ArcNode *firstarc; //指向第一条边
}VNode; //邻接表结点类型
typedef struct
{
VNode adjlist[MAXV]; //邻接表头结点数组
int n; //图中顶点数
int e; //图中边数
}AdjGraph; //完整的图邻接表类型
/*-------------------------邻接矩阵的基本运算算法---------------------------*/
/*------------由边数组A、顶点数n和边数e创建图的邻接矩阵g--------------------*/
void CreateMat(MatGraph &g, int A[MAXV][MAXV], int n, int e)
{
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];
}
/*------------输出邻接矩阵g--------------------*/
void DispMat(MatGraph g)
{
int i, j;
for(i = 0; i < g.n; i++)
{
for(j = 0; j < g.n; j++)
{
if(g.edges[i][j] != INF)
printf("%4d", g.edges[i][j]);
else
printf("%4s", "∞");
}
printf("\n");
}
}
/*-------------------------邻接表的基本运算算法---------------------------*/
/*-------------------由边数组A、顶点数n和边数e创建图的邻接表G--------------------*/
void CreateAdj(AdjGraph *&G, int A[MAXV][MAXV], int n, int e)
{
int i, j;
ArcNode *p;
G = (AdjGraph *)malloc(sizeof(AdjGraph));
for(i = 0; i < n; i++) //给邻接表中所有头结点的指针域置初值NULL
{
G->adjlist[i].firstarc = NULL;
}
for(i = 0; i < n; i++) //检查邻接矩阵中的每个元素
{
for(j = n - 1; j >= 0; j--)
{
if(A[i][j] != 0 && A[i][j] != INF) //存在一条边
{
p = (ArcNode *)malloc(sizeof(ArcNode)); //创建一个结点p
p->adjvex = j; //邻接点编号
p->weight = A[i][j]; //边的权重
p->nextarc = G->adjlist[i].firstarc; //采用头插法插入结点p
G->adjlist[i].firstarc = p;
}
}
}
G->n = n;
G->e = e;
}
/*-------------------输出邻接表G--------------------*/
void DispAdj(AdjGraph *G)
{
ArcNode *p;
for(int i = 0; i < G->n; i++)
{
p = G->adjlist[i].firstarc;
printf("%d: ", i);
while(p != NULL)
{
printf("%3d[%d]->", p->adjvex, p->weight); //邻接点编号[权重]
p = p->nextarc;
}
printf("∧\n");
}
}
/*-------------------销毁图的邻接表G--------------------*/
void DestroyAdj(AdjGraph *&G)
{
ArcNode *pre, *p;
for(int i = 0; i < G->n; i++)
{
pre = G->adjlist[i].firstarc; //pre指向第i个单链表的首结点
if(pre != NULL)
{
p = pre->nextarc;
while(p != NULL) //释放第i个单链表的所有边结点
{
free(pre);
pre = p;
p = p->nextarc;
}
free(pre);
}
}
free(G); //释放头结点数组
}
int visited[MAXV]; //全局数组
/**
* 功能:
* 求图G中从顶点v出发的所有深度优先遍历序列
* @param path:记录访问过的顶点序列
* @param d:记录访问的顶点数,其初值为0,当d=n时输出path中的访问序列
*
*/
void DFSALL(AdjGraph *G, int v, int path[], int d)
{
ArcNode *p;
visited[v] = 1; //置已访问标记
path[d] = v;
d++;
if(d == G->n) //如果已访问所有顶点,则输出访问序列
{
for(int k = 0; k < d; k++)
printf("%3d", path[k]);
printf("\n");
}
p = G->adjlist[v].firstarc; //p指向顶点v的第一个相邻点
while(p != NULL)
{
if(visited[p->adjvex] == 0) //若p->adjvex顶点未访问,递归访问它
{
DFSALL(G, p->adjvex, path, d);
}
p = p->nextarc; //找顶点v的下一个相邻点
}
visited[v] = 0;
}
int main(void)
{
AdjGraph *G;
int n = 5; //图顶点数
int e = 8; //图边数
int A[MAXV][MAXV] = {
{0, 1, 0, 1, 1}, {1, 0, 1, 1, 0},
{0, 1, 0, 1, 1}, {1, 1, 1, 0, 1},
{1, 0, 1, 1, 0}
};
CreateAdj(G, A, n, e);
printf("图的邻接表:\n");
DispAdj(G);
int path[MAXV];
int v = 1;
printf("从顶点%d出发的所有深度优先序列:\n", v);
DFSALL(G, v, path, 0);
printf("销毁图的邻接表\n");
DestroyAdj(G);
return 0;
}
输出结果:
图G的邻接表:
0: 1[1]-> 3[1]-> 4[1]->∧
1: 0[1]-> 2[1]-> 3[1]->∧
2: 1[1]-> 3[1]-> 4[1]->∧
3: 0[1]-> 1[1]-> 2[1]-> 4[1]->∧
4: 0[1]-> 2[1]-> 3[1]->∧
从顶点1出发的所有深度优先序列:
1 0 3 2 4
1 0 3 4 2
1 0 4 2 3
1 0 4 3 2
1 2 3 0 4
1 2 3 4 0
1 2 4 0 3
1 2 4 3 0
1 3 0 4 2
1 3 2 4 0
销毁图的邻接表