#include #include #include #define MaxSize 8 typedef struct ArcNode { //【边结点】 int adjvex; //该边所指向的顶点的位置 struct ArcNode* nextarc; //指向下一条边的指针 }ArcNode; typedef struct VNode { //【表头结点】 char data[3]; //顶点信息--每个顶点的数据是一个由3个字符组成的字符串(或字符数组)V0,V1 ArcNode* firstarc; //指向第一条依附该顶点的边的指针 }VNode; typedef struct { VNode vertices[MaxSize]; //邻接表(vertices为数组名) int vexnum, arcnum; //图的当前顶点数和边数 }ALGragh; //1、构建图:参考P151算法6.2 void InitList(ALGragh &G, char a[][3]) { int i, j; for (i = 0; i < G.vexnum; i++) { for (j = 0; j < 3; j++) G.vertices[i].data[j] = a[i][j]; //todo list //输入顶点值 G.vertices[i].firstarc = NULL; //todo list //初始化表头结点的指针域为NULL } printf("请输入各边所依附的两个顶点的位置\n"); for (int k = 0; k < G.arcnum; k++) { scanf("%d %d", &i, &j); //生成一个新的边结点*p1: ArcNode* p1 = (ArcNode*)malloc(sizeof(struct ArcNode)); p1->adjvex = j; p1->nextarc = G.vertices[i].firstarc; G.vertices[i].firstarc = p1; //todo list 设此邻接点序号为j,并将新结点*p1插入顶点vi的边表头部(头插法) //生成另一个对称的新的边结点*p2: ArcNode* p2 = (ArcNode*)malloc(sizeof(struct ArcNode)); p2->adjvex = i; p2->nextarc = G.vertices[j].firstarc; G.vertices[j].firstarc = p2; //todo list 设此邻接点序号为i,并将新结点*p2插入顶点vj的边表头部(头插法) } } //2、输出邻接表 void PrintInf(ALGragh G) { int i; ArcNode* p; //struct ArcNode* p; printf("输出图的邻接表:\n"); for (i = 0; i < G.vexnum; i++) { //G.vexnum表示图中的顶点数量。 printf("%s ", G.vertices[i].data); //打印当前顶点 i 的数据 (%s 被用于表示待插入的数据是字符串类型) for (p = G.vertices[i].firstarc; p != NULL; p = p->nextarc) //for循环遍历当前顶点 i 的所有邻接顶点,并打印这些邻接顶点。 printf("%d ", p->adjvex); printf("\n"); } } //3、对采用【邻接表】表示的图,做深度优先遍历:参考P157算法6.6 void DFS_AL(ALGragh G, int visited[], int v) { printf("%s ", G.vertices[v].data); // 访问第 v 个顶点 ArcNode* p; int w; visited[v] = 1; p = G.vertices[v].firstarc; //todo list //将 p 初始化为指向顶点 v 的第一个邻接点的指针 while (p != NULL) { //todo list //while循环:对v未被访问的邻接顶点w递归调用DFSTraverse 函数;并寻找v相对于w的下一个邻接点 w = p->adjvex; if (!visited[w]) { DFS_AL(G, visited, w); } p = p->nextarc; } } //4、深度优先遍历非连通图(也兼容连通图) : 参考P156算法6.4 (可用于计算连通分量的个数,但需要增加count变量,如下算法5) void DFSTraverse_AL(ALGragh G, int visited[]) { int v; for (v = 0; v < G.vexnum; v++) //初始化标记数组,置为0 visited[v] = 0; for (v = 0; v < G.vexnum; v++) if (!visited[v]) { //todo list 如果有顶点没有被访问,那就以它为起点遍历所在的连通分量 DFS_AL(G, visited, v); } printf("\n"); } //5、计算连通分量的个数 void Count(ALGragh G, int visited[]) { int count = 0, v; for (v = 0; v < G.vexnum; v++) //初始化标记数组,置为0 visited[v] = 0; for (v = 0; v < G.vexnum; v++) if (!visited[v]) { //todo list 如果有顶点没有被访问,那就以它为起点遍历所在的连通分量,连通分量个数加一 DFS_AL(G, visited, v); count++; } printf("\n"); printf("连通分量个数:%d\n", count); } //6、判断有无路径可达 void Judge(ALGragh G, int visited[], int v, int u) { for (int i = 0; i < G.vexnum; i++) visited[i] = 0; DFS_AL(G, visited, v); //todo list 以v作为起点,做深度优先遍历图,在此过程中不断将所有相互连接的邻接结点的visited[u]更新为1 if (visited[u] == 1){ printf("\n"); printf("V%d与V%d有路径可达!\n", v, u); } else{ printf("\n"); printf("V%d与V%d无路径可达!\n", v, u); } } int main() { int v, u; //j是边的数目,v、u为顶点位置 int choose = -1; //a是一个二维字符数组,存储顶点信息(字符串还得保存结尾的空字符\0,因此列数需要设为3) char a[MaxSize][3] = { "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7" }; int visited[MaxSize] = { 0 }; ALGragh G; G.vexnum = MaxSize; printf("*****************************************************\n"); printf("********** 实验八 *******\n"); printf("*****************************************************\n"); printf("********** 1.构建图 *******\n"); printf("********** 2.输出邻接表 *******\n"); printf("********** 3.深度优先遍历的结果 *******\n"); printf("********** 4.判断两个点之间是否有路径可达 *******\n"); printf("********** 5.输出连通分量的个数 *******\n"); printf("********** 0.退出 *******\n"); printf("*****************************************************\n"); while(choose) { printf("请输入你的选择项:"); scanf("%d", &choose); switch(choose){ case 1: printf("输入边数:"); scanf("%d", &G.arcnum); InitList(G, a); break; case 2: PrintInf(G); break; case 3: printf("深度优先遍历结果:"); DFSTraverse_AL(G, visited); // 3 深度优先遍历图 //DFS_AL(G, visited,v); //如果是一个连通图,直接调用 DFS_AL也可以得到正确结果 printf("\n"); break; case 4: printf("输入要判断的两个点:"); scanf("%d %d", &v, &u); Judge(G, visited, v, u); break; case 5: Count(G, visited); break; case 0: exit(0); break; } } return 0; }