发布时间 : 星期日 文章求一个无向图G的连通分量的个数更新完毕开始阅读
《数据结构》实验报告
实验内容: (一)判断一个图有无回路
(二)求一个无向图G的连通分量的个数
一、 目的和要求(需求分析):
1、 了解图的定义和图的存储结构。 2、 熟悉掌握图的邻接矩阵和邻接表。
3、 理解图的遍历算法---深度优先搜索和广度优先搜索。 4、 学会编程处理图的连通性问题。 二、程序设计的基本思想,原理和算法描述:
(包括程序的结构,数据结构,输入/输出设计,符号名说明等)
判断一个图有无回路:
在程序设计中,先必须确定所要创建的图是有向还是无向,是图还是网,其次再根据各自的特点,用连接表来实现创建。
在有向图中,先找出入度为0的顶点,删除与这个顶点相关联的边(出边),将与这些边相关的其它顶点的入度减1,循环直到没有入度为0的顶点。如果此时还有未被删除的顶点,则必然存在环路,否则不存在回路。
无向图则可以转化为:
如果存在回路,则必然存在一个子图,是一个回路。因此回路中所有定点的度>=2。 第一步:删除所有度<=1的顶点及相关边,并将另外与这些边相关的其它顶点的度减1。 第二步:将度数变为1的顶点排入队列,并从该队列中(使用栈)取出一个顶点,并重复步骤一。
如果最后还有未删除的顶点,则存在回路,否则没有。
求一个无向图G的连通分量的个数:
用连接表创建图,对于非连通图,则需从多个顶点出发进行搜索,而每一次从一个新的起始点出发进行搜索过程中得到的顶点访问序列恰为其各个连通分量中的顶点集。所以在设计中,为了统计出无向图中的连通分量个数,则因在其深度优先所搜无向图时对函数DFSTraverse(ALGraph G)调用DFS次数进行统计,其结果便为无向图中连通分量个数。 三、调试和运行程序过程中产生的问题及采取的措施:
在调试和运行求一个无向图G的连通分量的个数程序时,由于执行语句块
void DFSTraverse(ALGraph G)先于void DFS(ALGraph G,int v), 而void DFSTraverse(ALGraph G)内调用了DFS( ),因此计算机无法正确运行,将两者顺序进行了交换,程序便实现了其功能,且运行正常。 四、源程序及注释:
判断一个图有无回路:
#include
// 输出有向图的一个拓扑序列。 // 图的邻接表存储表示
#define MAX_NAME 3 // 顶点字符串的最大长度+1 #define MAX_VERTEX_NUM 20
#define STACK_INIT_SIZE 10 // 存储空间初始分配量 #define STACKINCREMENT 2 // 存储空间分配增量
typedef int InfoType; // 存放网的权值 typedef char VertexType[MAX_NAME]; // 字符串类型
typedef enum{DG,DN,AG,AN}GraphKind; // {有向图,有向网,无向图,无向网}
typedef struct ArcNode { int adjvex;
// 该弧所指向的顶点的位置
struct ArcNode *nextarc; InfoType *info;
// 表结点
// 指向下一条弧的指针
// 网的权值指针)
}ArcNode;
typedef struct VNode { VertexType data; ArcNode *firstarc;
// 顶点信息
// 第一个表结点的地址,指向第一条依附该顶点的弧的
指针
}VNode,AdjList[MAX_VERTEX_NUM];// 头结点
typedef struct {
AdjList vertices; int vexnum,arcnum; int kind;
// 图的当前顶点数和弧数
// 图的种类标志
}ALGraph;
// 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。 int LocateVex(ALGraph G,VertexType u) {
int i;
for(i=0;i return -1; } // 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图)。 int CreateGraph(ALGraph *G) { int i,j,k; int w; // 权值 VertexType va,vb; ArcNode *p; printf(\请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): \scanf(\ printf(\请输入图的顶点数和边数:(空格)\\n\ scanf(\ printf(\请输入%d个顶点的值(小于%d个字符):\\n\for(i = 0; i < (*G).vexnum; ++i) // 构造顶点向量 { scanf(\(*G).vertices[i].firstarc = NULL; } if((*G).kind == 1 || (*G).kind == 3) // 网 printf(\请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\\n\else // 图 printf(\请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\\n\for(k = 0;k < (*G).arcnum; ++k) // 构造表结点链表 { if((*G).kind==1||(*G).kind==3) // 网 scanf(\else // 图 scanf(\i = LocateVex(*G,va); // 弧尾 j = LocateVex(*G,vb); // 弧头 p = (ArcNode*)malloc(sizeof(ArcNode)); p->adjvex = j; if((*G).kind == 1 || (*G).kind == 3) // 网 { } else p->info = NULL; // 图 p->nextarc = (*G).vertices[i].firstarc; // 插在表头 (*G).vertices[i].firstarc = p; p->info = (int *)malloc(sizeof(int)); *(p->info) = w; if((*G).kind >= 2) // 无向图或网,产生第二个表结点 { } p = (ArcNode*)malloc(sizeof(ArcNode)); p->adjvex = i; if((*G).kind == 3) // 无向网 { } p->info = (int*)malloc(sizeof(int)); *(p->info) = w; else p->info = NULL; // 无向图 p->nextarc = (*G).vertices[j].firstarc; // 插在表头 (*G).vertices[j].firstarc = p; } return 1; } void Display(ALGraph G) // { int i; ArcNode *p; switch(G.kind) { case DG: printf(\有向图\\n\ break; case DN: printf(\有向网\\n\ break; case AG: printf(\无向图\\n\ break; case AN: printf(\无向网\\n\ 输出图的邻接表G。 } printf(\个顶点:\\n\.vexnum); for(i = 0; i < G.vexnum; ++i) printf(\.vertices[i].data); printf(\条弧(边):\\n\.arcnum); for(i = 0; i < G.vexnum; i++) { p = G.vertices[i].firstarc; while(p) { if(G.kind <= 1) // 有向 {