💡 <07 图>习题代码

This commit is contained in:
康建伟
2020-02-18 03:44:06 +08:00
parent 50301fb446
commit 1a4ce70ff7
681 changed files with 69938 additions and 0 deletions
@@ -0,0 +1,181 @@
#include <stdio.h>
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
#include "ALGraph.h" //**▲07 图**//
/*
* 创建图/表
*/
Status CreateGraph_7_14(ALGraph* G, char* path[]);
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_16(ALGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_16(ALGraph* G, VertexType v);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_16(ALGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_16(ALGraph* G, VertexType v, VertexType w);
int main(int argc, char* argv[]) {
ALGraph G;
printf("████████ 创建并输出图/网...\n");
{
char* path[4];
path[0] = "TestData_DG.txt";
path[1] = "TestData_DN.txt";
path[2] = "TestData_UDG.txt";
path[3] = "TestData_UDN.txt";
CreateGraph_7_14(&G, path);
PrintGraph(G);
printf("\n");
}
printf("████████ 删除顶点...\n");
{
VertexType v = 'X';
printf("删除顶点 '%c' 后的图为:\n", v);
DeleteVex_7_16(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入顶点...\n");
{
VertexType v = 'Y';
printf("插入顶点 '%c' 后的图为:\n", v);
InsertVex_7_16(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入边/弧...\n");
{
// 注:<E, B>是重复的边
VertexType v[10] = {'B', 'C', 'E', 'Y', 'Y', 'Y', 'D', 'D', 'E', 'E'};
VertexType w[10] = {'Y', 'Y', 'Y', 'A', 'B', 'D', 'C', 'A', 'B', 'D'};
InfoType info[10] = {{8}, {5}, {1}, {11}, {2}, {6}, {3}, {7}, {2}, {9}};
int k;
// 图
if(G.kind == DG || G.kind == UDG) {
for(k = 0; k < 10; k++) {
printf("插入无权值的边:<%c, %c>...\n", v[k], w[k]);
InsertArc_7_16(&G, v[k], w[k]);
}
// 网
} else if(G.kind == DN || G.kind == UDN) {
for(k = 0; k < 10; k++) {
printf("插入带权值的边:<%c, %c, %d>...\n", v[k], w[k], info[k].weight);
InsertArc_7_16(&G, v[k], w[k], &info[k]);
}
} else {
return ERROR;
}
PrintGraph(G);
printf("\n");
}
printf("████████ 删除边/弧...\n");
{
VertexType v[3] = {'D', 'E', 'F'};
VertexType w[3] = {'A', 'B', 'B'};
int k;
for(k = 0; k < 3; k++) {
printf("删除边:<%c, %c>...\n", v[k], w[k]);
DeleteArc_7_16(&G, v[k], w[k]);
}
PrintGraph(G);
printf("\n");
}
return 0;
}
/*
* 创建图/表
*/
Status CreateGraph_7_14(ALGraph* G, char* path[]) {
return CreateGraph(G, path);
}
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_16(ALGraph* G, VertexType v) {
return InsertVex(G, v);
}
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_16(ALGraph* G, VertexType v) {
return DeleteVex(G, v);
}
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_16(ALGraph* G, VertexType v, VertexType w, ...) {
va_list ap;
InfoType* info = NULL; // 边/弧的附加信息
// 如果边/弧上存在附加信息
if(IncInfo) {
va_start(ap, w); // 在w后查询首个可变参数
info = va_arg(ap, InfoType*); // 获取附加信息
va_end(ap);
}
return InsertArc(G, v, w, info);
}
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_16(ALGraph* G, VertexType v, VertexType w) {
return DeleteArc(G, v, w);
}
File diff suppressed because it is too large Load Diff
+162
View File
@@ -0,0 +1,162 @@
/*==================
* 图的邻接表存储表示
===================*/
#ifndef ALGRAPH_H
#define ALGRAPH_H
#include <stdio.h>
#include <string.h> // 提供memset、strcmp 原型
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
/*
* 注:
*
* 通常来讲,无权图被简称为【图】,有权图被简称为【网】。
* 无向图/网中的顶点关系被称为【边】,有向图/网中的顶点关系被称为【弧】,并区分弧头与弧尾。
* 实际表述中,未必会严格遵守以上命名。
*
* 当前结构适合存储边/弧比较稀疏的图/网。
*
* ★ 插入边/弧的信息时,这里的实现是按"升序"插入的,这使得插入的弧是按"升序"排列的。
*/
/* 宏定义 */
#define MAX_VERTEX_NUM 26 // 最大顶点个数
// 图的类型
typedef enum {
DG, // 0-有向图
DN, // 1-有向网(带权值)
UDG, // 2-无向图
UDN // 3-无向网(带权值)
} GraphKind;
// 顶点类型
typedef char VertexType;
// 边/弧的相关附加信息
typedef struct {
/*
* 注:
* 教材中给出的结构只考虑了无权图,而没考虑有权图(网)。
* 这里为了把“网”的情形也考虑进去,特在附加信息中增加了"权重"属性。
*/
int weight;
} InfoType;
/* 边/弧结点 */
typedef struct ArcNode {
int adjvex; // 该弧所指向的顶点的位置
struct ArcNode* nextarc; // 指向下一条弧的指针
InfoType* info; // 弧的附加信息,通常忽略
} ArcNode;
// 每个链表的头结点
typedef struct VNode {
VertexType data; // 顶点信息
ArcNode* firstarc; // 指向第一条依附该顶点的弧的指针
} VNode;
/* 图的邻接表存储表示类型定义 */
typedef struct {
VNode vertices[MAX_VERTEX_NUM]; // 邻接表
int vexnum, arcnum; // 图/网的顶点数和弧数
GraphKind kind; // 图的类型标志
} ALGraph;
// 边/弧上是否存在附加信息
extern Boolean IncInfo;
/*
* 创建
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL,或path[kind]为""。
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateGraph(ALGraph* G, char* path[]);
/*
* 构造有向图
*/
static Status CreateDG(ALGraph* G);
/*
* 构造有向网
*/
static Status CreateDN(ALGraph* G);
/*
* 构造无向图
*/
static Status CreateUDG(ALGraph* G);
/*
* 构造无向网
*/
static Status CreateUDN(ALGraph* G);
/*
* 录入边/弧的相关附加信息
*/
static void Input(ALGraph G, InfoType** info);
/*
* 查找
*
* 返回顶点u在图/网中的位置
*/
int LocateVex(ALGraph G, VertexType u);
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex(ALGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex(ALGraph* G, VertexType v);
/*
* 构造一个边/弧结点(仅限内部使用)
*/
static ArcNode* newArcNodePtr(int adjvex, ArcNode* nextarc, InfoType* info);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
* 对于图/网来说,可以在可变参数中列出边/弧的附加信息。
*
* 注:此处接收的参数与MGraph有些不一样:网的附加信息中包含了各条边/弧的权值。
*/
Status InsertArc(ALGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边/弧<v, w>
*/
Status DeleteArc(ALGraph* G, VertexType v, VertexType w);
/*
* 以图形化形式输出当前结构
*/
void PrintGraph(ALGraph G);
#endif
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(07.14+07.16 ALGraph.h ALGraph.c 07.14+07.16.c)
# 链接公共库
target_link_libraries(07.14+07.16 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
@@ -0,0 +1,6 @@
图类型→0(有向图)
顶点数→6
弧数→14
弧是否带有其他信息→0
顶点集→【AXBCDE】
弧的集合→【A,B】【A,C】【A,D】【B,C】【B,D】【B,E】【C,B】【C,E】【C,X】【E,A】【E,D】【E,X】【X,A】【X,D】
@@ -0,0 +1,6 @@
图类型→1(有向网)
顶点数→6
弧数→14
弧是否带有其他信息→1
顶点集→【AXBCDE】
弧的集合→【A,B,3】【A,C,8】【A,D,11】【B,C,7】【B,D,4】【B,E,1】【C,B,5】【C,E,17】【C,X,3】【E,A,6】【E,D,4】【E,X,2】【X,A,8】【X,D,10】
@@ -0,0 +1,6 @@
图类型→2(无向图)
顶点数→6
边数→13
边是否带有其他信息→0
顶点集→【AXBCDE】
边的集合→【A,B】【A,C】【A,D】【B,C】【B,D】【B,E】【C,E】【C,X】【E,A】【E,D】【E,X】【X,A】【X,D】
@@ -0,0 +1,6 @@
图类型→3(无向网)
顶点数→6
边数→13
边是否带有其他信息→1
顶点集→【AXBCDE】
边的集合→【A,B,3】【A,C,8】【A,D,11】【B,C,7】【B,D,4】【B,E,1】【C,E,17】【C,X,3】【E,A,6】【E,D,4】【E,X,2】【X,A,8】【X,D,10】
+191
View File
@@ -0,0 +1,191 @@
#include <stdio.h>
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
#include "MGraph.h" //**▲07 图**//
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_15(MGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_15(MGraph* G, VertexType v);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_15(MGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_15(MGraph* G, VertexType v, VertexType w);
int main(int argc, char* argv[]) {
MGraph G;
printf("████████ 创建并输出图/网...\n");
{
char* path[4];
path[0] = "TestData_DG.txt";
path[1] = "TestData_DN.txt";
path[2] = "TestData_UDG.txt";
path[3] = "TestData_UDN.txt";
CreateGraph(&G, path);
PrintGraph(G);
printf("\n");
}
printf("████████ 删除顶点...\n");
{
VertexType v = 'X';
printf("删除顶点 '%c' 后的图为:\n", v);
DeleteVex_7_15(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入顶点...\n");
{
VertexType v = 'Y';
printf("插入顶点 '%c' 后的图为:\n", v);
InsertVex_7_15(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入边/弧...\n");
{
// 注:<E, B>是重复的边
VertexType v[10] = {'B', 'C', 'E', 'Y', 'Y', 'Y', 'D', 'D', 'E', 'E'};
VertexType w[10] = {'Y', 'Y', 'Y', 'A', 'B', 'D', 'C', 'A', 'B', 'D'};
VRType adj[10] = {8, 5, 1, 11, 2, 6, 3, 7, 2, 9};
int k;
// 图
if(G.kind == DG || G.kind == UDG) {
for(k = 0; k < 10; k++) {
printf("插入无权值的边:<%c, %c>...\n", v[k], w[k]);
InsertArc_7_15(&G, v[k], w[k]);
}
// 网
} else if(G.kind == DN || G.kind == UDN) {
for(k = 0; k < 10; k++) {
printf("插入带权值的边:<%c, %c, %d>...\n", v[k], w[k], adj[k]);
InsertArc_7_15(&G, v[k], w[k], adj[k]);
}
} else {
return ERROR;
}
PrintGraph(G);
printf("\n");
}
printf("████████ 删除边/弧...\n");
{
VertexType v[3] = {'D', 'E', 'F'};
VertexType w[3] = {'A', 'B', 'B'};
int k;
for(k = 0; k < 3; k++) {
printf("删除边:<%c, %c>...\n", v[k], w[k]);
DeleteArc_7_15(&G, v[k], w[k]);
}
PrintGraph(G);
printf("\n");
}
return 0;
}
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_15(MGraph* G, VertexType v) {
return InsertVex(G, v);
}
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_15(MGraph* G, VertexType v) {
return DeleteVex(G, v);
}
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_15(MGraph* G, VertexType v, VertexType w, ...) {
va_list ap;
VRType adj;
InfoType* info = NULL; // 边/弧的附加信息
// 图
if((*G).kind == DG || (*G).kind == UDG) {
// 如果边/弧上存在附加信息
if(IncInfo) {
va_start(ap, w); // 在w后查询首个可变参数
info = va_arg(ap, InfoType*); // 获取附加信息
va_end(ap);
}
return InsertArc(G, v, w, info);
// 网
} else if((*G).kind == DN || (*G).kind == UDN) {
va_start(ap, w); // 在w后查询首个可变参数
adj = va_arg(ap, VRType); // 获取权值信息
// 如果边/弧上存在附加信息
if(IncInfo) {
info = va_arg(ap, InfoType*); // 获取附加信息
}
va_end(ap);
return InsertArc(G, v, w, adj, info);
} else {
return ERROR;
}
}
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_15(MGraph* G, VertexType v, VertexType w) {
return DeleteArc(G, v, w);
}
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(07.15 MGraph.h MGraph.c 07.15.c)
# 链接公共库
target_link_libraries(07.15 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
File diff suppressed because it is too large Load Diff
+160
View File
@@ -0,0 +1,160 @@
/*=================================
* 图的数组(邻接矩阵)存储表示
*
* 包含算法: 7.1、7.2、7.4、7.5、7.6
==================================*/
#ifndef MGRAPH_H
#define MGRAPH_H
#include <stdio.h>
#include <limits.h> // 提供宏INT_MAX
#include <string.h> // 提供memset、strcmp 原型
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
/*
* 注:
*
* 通常来讲,无权图被简称为【图】,有权图被简称为【网】。
* 无向图/网中的顶点关系被称为【边】,有向图/网中的顶点关系被称为【弧】,并区分弧头与弧尾。
* 实际表述中,未必会严格遵守以上命名。
*/
/* 宏定义 */
#define INFINITE INT_MAX // 最大值,用来表示网中的两个顶点不直接连接
#define MAX_VERTEX_NUM 26 // 最大顶点个数
// 图的类型
typedef enum {
DG, // 0-有向图
DN, // 1-有向网(带权值)
UDG, // 2-无向图
UDN // 3-无向网(带权值)
} GraphKind;
// 顶点类型
typedef char VertexType;
/*
* 顶点关系类型
*
* 在无权图中,该值通常为0或1,表示两顶点是否直接连通;
* 在有权图中,该值通常为权值。
*/
typedef int VRType;
// 边的相关附加信息
typedef struct {
// 如果有的话,后续会添加相应的属性
} InfoType;
// 边的类型,每条边上可能有附加信息info
typedef struct ArcCell {
VRType adj; // 顶点关系,在有权图跟无权图中的含义不同
InfoType* info; // 边的附加信息,通常忽略
} ArcCell;
/* 图/网的数组(邻接矩阵)存储表示类型定义 */
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量
ArcCell arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵
int vexnum, arcnum; // 图/网的顶点数和弧数
GraphKind kind; // 图的类型标志
} MGraph;
// 边/弧上是否存在附加信息
extern Boolean IncInfo;
/*
* ████████ 算法7.1 ████████
*
* 创建
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL,或path[kind]为""。
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateGraph(MGraph* G, char* path[]);
/*
* 构造有向图
*/
static Status CreateDG(MGraph* G);
/*
* 构造有向网
*/
static Status CreateDN(MGraph* G);
/*
* 构造无向图
*/
static Status CreateUDG(MGraph* G);
/*
* ████████ 算法7.2 ████████
*
* 构造无向网
*/
static Status CreateUDN(MGraph* G);
/*
* 录入边的相关附加信息
*/
static void Input(MGraph G, InfoType** info);
/*
* 查找
*
* 返回顶点u在图/网中的位置
*/
int LocateVex(MGraph G, VertexType u);
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex(MGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex(MGraph* G, VertexType v);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc(MGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc(MGraph* G, VertexType v, VertexType w);
/*
* 以图形化形式输出当前结构
*
* 注:在图/网中,使用"-"来表示两顶点不直接连通
*/
void PrintGraph(MGraph G);
#endif
+6
View File
@@ -0,0 +1,6 @@
图类型→0(有向图)
顶点数→6
弧数→14
弧是否带有其他信息→0
顶点集→【AXBCDE】
弧的集合→【A,B】【A,C】【A,D】【B,C】【B,D】【B,E】【C,B】【C,E】【C,X】【E,A】【E,D】【E,X】【X,A】【X,D】
+6
View File
@@ -0,0 +1,6 @@
图类型→1(有向网)
顶点数→6
弧数→14
弧是否带有其他信息→0
顶点集→【AXBCDE】
弧的集合→【A,B,3】【A,C,8】【A,D,11】【B,C,7】【B,D,4】【B,E,1】【C,B,5】【C,E,17】【C,X,3】【E,A,6】【E,D,4】【E,X,2】【X,A,8】【X,D,10】
@@ -0,0 +1,6 @@
图类型→2(无向图)
顶点数→6
边数→13
边是否带有其他信息→0
顶点集→【AXBCDE】
边的集合→【A,B】【A,C】【A,D】【B,C】【B,D】【B,E】【C,E】【C,X】【E,A】【E,D】【E,X】【X,A】【X,D】
@@ -0,0 +1,6 @@
图类型→3(无向网)
顶点数→6
边数→13
边是否带有其他信息→0
顶点集→【AXBCDE】
边的集合→【A,B,3】【A,C,8】【A,D,11】【B,C,7】【B,D,4】【B,E,1】【C,E,17】【C,X,3】【E,A,6】【E,D,4】【E,X,2】【X,A,8】【X,D,10】
+169
View File
@@ -0,0 +1,169 @@
#include <stdio.h>
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
#include "OLGraph.h" //**▲07 图**//
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_17(OLGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_17(OLGraph* G, VertexType v);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_17(OLGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_17(OLGraph* G, VertexType v, VertexType w);
int main(int argc, char* argv[]) {
OLGraph G;
printf("████████ 创建并输出图/网...\n");
{
char* path[4];
path[0] = "TestData_DG.txt";
path[1] = "TestData_DN.txt";
path[2] = "TestData_UDG.txt";
path[3] = "TestData_UDN.txt";
CreateGraph(&G, path);
PrintGraph(G);
printf("\n");
}
printf("████████ 删除顶点...\n");
{
VertexType v = 'X';
printf("删除顶点 '%c' 后的图为:\n", v);
DeleteVex_7_17(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入顶点...\n");
{
VertexType v = 'Y';
printf("插入顶点 '%c' 后的图为:\n", v);
InsertVex_7_17(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入边/弧...\n");
{
// 注:<E, B>是重复的边
VertexType v[10] = {'B', 'C', 'E', 'Y', 'Y', 'Y', 'D', 'D', 'E', 'E'};
VertexType w[10] = {'Y', 'Y', 'Y', 'A', 'B', 'D', 'C', 'A', 'B', 'D'};
InfoType info[10] = {{8}, {5}, {1}, {11}, {2}, {6}, {3}, {7}, {2}, {9}};
int k;
// 图
if(G.kind == DG || G.kind == UDG) {
for(k = 0; k < 10; k++) {
printf("插入无权值的边:<%c, %c>...\n", v[k], w[k]);
InsertArc_7_17(&G, v[k], w[k]);
}
// 网
} else if(G.kind == DN || G.kind == UDN) {
for(k = 0; k < 10; k++) {
printf("插入带权值的边:<%c, %c, %d>...\n", v[k], w[k], info[k].weight);
InsertArc_7_17(&G, v[k], w[k], &info[k]);
}
} else {
return ERROR;
}
PrintGraph(G);
printf("\n");
}
printf("████████ 删除边/弧...\n");
{
VertexType v[3] = {'D', 'E', 'F'};
VertexType w[3] = {'A', 'B', 'B'};
int k;
for(k = 0; k < 3; k++) {
printf("删除边:<%c, %c>...\n", v[k], w[k]);
DeleteArc_7_17(&G, v[k], w[k]);
}
PrintGraph(G);
printf("\n");
}
return 0;
}
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_17(OLGraph* G, VertexType v) {
return InsertVex(G, v);
}
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_17(OLGraph* G, VertexType v) {
return DeleteVex(G, v);
}
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_17(OLGraph* G, VertexType v, VertexType w, ...) {
va_list ap;
InfoType* info = NULL; // 边/弧的附加信息
// 如果边/弧上存在附加信息
if(IncInfo) {
va_start(ap, w); // 在w后查询首个可变参数
info = va_arg(ap, InfoType*); // 获取附加信息
va_end(ap);
}
return InsertArc(G, v, w, info);
}
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_17(OLGraph* G, VertexType v, VertexType w) {
return DeleteArc(G, v, w);
}
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(07.17 OLGraph.h OLGraph.c 07.17.c)
# 链接公共库
target_link_libraries(07.17 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
File diff suppressed because it is too large Load Diff
+178
View File
@@ -0,0 +1,178 @@
/*====================
* 图的十字链表存储表示
*
* 包含算法: 7.3
====================*/
#ifndef OLGRAPH_H
#define OLGRAPH_H
#include <stdio.h>
#include <string.h> // 提供memset、strcmp 原型
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
/*
* 注:
*
* 通常来讲,无权图被简称为【图】,有权图被简称为【网】。
* 无向图/网中的顶点关系被称为【边】,有向图/网中的顶点关系被称为【弧】,并区分弧头与弧尾。
* 实际表述中,未必会严格遵守以上命名。
*
* 当前结构适合存储有向图。
*
* ★ 插入边/弧的信息时,这里的实现是按"升序"插入的,这使得插入的弧是按"升序"排列的。
*/
/* 宏定义 */
#define MAX_VERTEX_NUM 26 // 最大顶点个数
// 图的类型
typedef enum {
DG, // 0-有向图
DN, // 1-有向网(带权值)
UDG, // 2-无向图
UDN // 3-无向网(带权值)
} GraphKind;
// 顶点类型
typedef char VertexType;
// 边/弧的相关附加信息
typedef struct {
/*
* 注:
* 教材中给出的结构只考虑了无权图,而没考虑有权图(网)。
* 这里为了把“网”的情形也考虑进去,特在附加信息中增加了"权重"属性。
*/
int weight;
} InfoType;
/* 边/弧结点 */
typedef struct ArcBox {
int tailvex; // 弧头顶点位置
int headvex; // 弧尾顶点位置
struct ArcBox* hlink; // 指向下一个拥有相同弧头的弧
struct ArcBox* tlink; // 指向下一个拥有相同弧尾的弧
InfoType* info; // 该弧的相关附加信息
} ArcBox;
// 每个横向链表的头结点
typedef struct VexNode {
VertexType data; // 顶点
ArcBox* firstin; // 指向该顶点的第一条入弧
ArcBox* firstout; // 指向该顶点的第一条出弧
} VexNode;
/* 图的十字链表存储表示类型定义 */
typedef struct {
VexNode xlist[MAX_VERTEX_NUM]; // 表头向量
int vexnum, arcnum; // 顶点数和弧数
GraphKind kind; // 图的类型标志
} OLGraph;
// 边/弧上是否存在附加信息
extern Boolean IncInfo;
/*
* 创建
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL,或path[kind]为""。
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateGraph(OLGraph* G, char* path[]);
/*
* ████████ 算法7.3 ████████
*
* 构造有向图
*
* 注:
* 教材中使用了头插法来插入弧,这种做法的唯一优点是插入方便,
* 但是在涉及到删除或查找时,效率较低;
* 而且,"头插法"依赖输入的顺序,如果输入的边/弧是乱序的,
* 则最终构造出的图/网中的边/弧也是无序的。
*
* 为了克服以上缺点,这里改用"升序"插入法,保证插入的弧是"升序"的。
* 但同时,这样做会使"插入"算法变得较为复杂。
*/
static Status CreateDG(OLGraph* G);
/*
* 构造有向网
*/
static Status CreateDN(OLGraph* G);
/*
* 构造无向图
*/
static Status CreateUDG(OLGraph* G);
/*
* 构造无向网
*/
static Status CreateUDN(OLGraph* G);
/*
* 录入弧的相关附加信息
*/
static void Input(OLGraph G, InfoType** info);
/*
* 查找
*
* 返回顶点u在图/网中的位置
*/
int LocateVex(OLGraph G, VertexType u);
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex(OLGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex(OLGraph* G, VertexType v);
/*
* 构造一个边/弧结点(仅限内部使用)
*/
static ArcBox* newArcBoxPtr(int tailvex, int headvex, ArcBox* hlink, ArcBox* tlink, InfoType* info);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
* 对于图/网来说,可以在可变参数中列出边/弧的附加信息。
*
* 注:此处接收的参数与MGraph有些不一样:网的附加信息中包含了各条边/弧的权值。
*/
Status InsertArc(OLGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边/弧<v, w>
*/
Status DeleteArc(OLGraph* G, VertexType v, VertexType w);
/*
* 以图形化形式输出当前结构
*/
void PrintGraph(OLGraph G);
#endif
+6
View File
@@ -0,0 +1,6 @@
图类型→0(有向图)
顶点数→6
弧数→14
弧是否带有其他信息→0
顶点集→【AXBCDE】
弧的集合→【A,B】【A,C】【A,D】【B,C】【B,D】【B,E】【C,B】【C,E】【C,X】【E,A】【E,D】【E,X】【X,A】【X,D】
+6
View File
@@ -0,0 +1,6 @@
图类型→1(有向网)
顶点数→6
弧数→14
弧是否带有其他信息→1
顶点集→【AXBCDE】
弧的集合→【A,B,3】【A,C,8】【A,D,11】【B,C,7】【B,D,4】【B,E,1】【C,B,5】【C,E,17】【C,X,3】【E,A,6】【E,D,4】【E,X,2】【X,A,8】【X,D,10】
@@ -0,0 +1,6 @@
图类型→2(无向图)
顶点数→6
边数→13
边是否带有其他信息→0
顶点集→【AXBCDE】
边的集合→【A,B】【A,C】【A,D】【B,C】【B,D】【B,E】【C,E】【C,X】【E,A】【E,D】【E,X】【X,A】【X,D】
@@ -0,0 +1,6 @@
图类型→3(无向网)
顶点数→6
边数→13
边是否带有其他信息→1
顶点集→【AXBCDE】
边的集合→【A,B,3】【A,C,8】【A,D,11】【B,C,7】【B,D,4】【B,E,1】【C,E,17】【C,X,3】【E,A,6】【E,D,4】【E,X,2】【X,A,8】【X,D,10】
@@ -0,0 +1,181 @@
#include <stdio.h>
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
#include "AMLGraph.h" //**▲07 图**//
/*
* 创建图/表
*/
Status CreateGraph_7_19(AMLGraph* G, char* path[]);
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_18(AMLGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_18(AMLGraph* G, VertexType v);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_18(AMLGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_18(AMLGraph* G, VertexType v, VertexType w);
int main(int argc, char* argv[]) {
AMLGraph G;
printf("████████ 创建并输出图/网...\n");
{
char* path[4];
path[0] = "";
path[1] = "";
path[2] = "TestData_UDG.txt";
path[3] = "TestData_UDN.txt";
CreateGraph_7_19(&G, path);
PrintGraph(G);
printf("\n");
}
printf("████████ 删除顶点...\n");
{
VertexType v = 'X';
printf("删除顶点 '%c' 后的图为:\n", v);
DeleteVex_7_18(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入顶点...\n");
{
VertexType v = 'Y';
printf("插入顶点 '%c' 后的图为:\n", v);
InsertVex_7_18(&G, v);
PrintGraph(G);
printf("\n");
}
printf("████████ 插入边/弧...\n");
{
// 注:<E, B>是重复的边
VertexType v[10] = {'B', 'C', 'E', 'Y', 'Y', 'Y', 'D', 'D', 'E', 'E'};
VertexType w[10] = {'Y', 'Y', 'Y', 'A', 'B', 'D', 'C', 'A', 'B', 'D'};
InfoType info[10] = {{8}, {5}, {1}, {11}, {2}, {6}, {3}, {7}, {2}, {9}};
int k;
// 图
if(G.kind == DG || G.kind == UDG) {
for(k = 0; k < 10; k++) {
printf("插入无权值的边:<%c, %c>...\n", v[k], w[k]);
InsertArc_7_18(&G, v[k], w[k]);
}
// 网
} else if(G.kind == DN || G.kind == UDN) {
for(k = 0; k < 10; k++) {
printf("插入带权值的边:<%c, %c, %d>...\n", v[k], w[k], info[k].weight);
InsertArc_7_18(&G, v[k], w[k], &info[k]);
}
} else {
return ERROR;
}
PrintGraph(G);
printf("\n");
}
printf("████████ 删除边/弧...\n");
{
VertexType v[3] = {'D', 'E', 'F'};
VertexType w[3] = {'A', 'B', 'B'};
int k;
for(k = 0; k < 3; k++) {
printf("删除边:<%c, %c>...\n", v[k], w[k]);
DeleteArc_7_18(&G, v[k], w[k]);
}
PrintGraph(G);
printf("\n");
}
return 0;
}
/*
* 创建图/表
*/
Status CreateGraph_7_19(AMLGraph* G, char* path[]) {
return CreateGraph(G, path);
}
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex_7_18(AMLGraph* G, VertexType v) {
return InsertVex(G, v);
}
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex_7_18(AMLGraph* G, VertexType v) {
return DeleteVex(G, v);
}
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
*
* 对于图来说,可以在可变参数中列出边/弧的附加信息;
* 对于网来说,可以在可变参数中依次列出边/弧的权值以及附加信息。
*/
Status InsertArc_7_18(AMLGraph* G, VertexType v, VertexType w, ...) {
va_list ap;
InfoType* info = NULL; // 边/弧的附加信息
// 如果边/弧上存在附加信息
if(IncInfo) {
va_start(ap, w); // 在w后查询首个可变参数
info = va_arg(ap, InfoType*); // 获取附加信息
va_end(ap);
}
return InsertArc(G, v, w, info);
}
/*
* 删除边/弧<v, w>
*
* 此删除只是更新边/弧的连通关系
*/
Status DeleteArc_7_18(AMLGraph* G, VertexType v, VertexType w) {
return DeleteArc(G, v, w);
}
File diff suppressed because it is too large Load Diff
+162
View File
@@ -0,0 +1,162 @@
/*=====================
* 图的邻接多重表存储表示
======================*/
#ifndef AMLGRAPH_H
#define AMLGRAPH_H
#include <stdio.h>
#include <string.h> // 提供memset、strcmp 原型
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
/*
* 注:
*
* 通常来讲,无权图被简称为【图】,有权图被简称为【网】。
* 无向图/网中的顶点关系被称为【边】,有向图/网中的顶点关系被称为【弧】,并区分弧头与弧尾。
* 实际表述中,未必会严格遵守以上命名。
*
* 当前结构适合存储无向图/网。
*
* ★ 插入边/弧的信息时,这里的实现是按"升序"插入的,这使得插入的弧是按"升序"排列的。
*/
/* 宏定义 */
#define MAX_VERTEX_NUM 26 // 最大顶点个数
// 图的类型
// 图的类型
typedef enum {
DG, // 0-有向图;此处不支持
DN, // 1-有向网(带权值);此处不支持
UDG, // 2-无向图
UDN // 3-无向网(带权值)
} GraphKind;
/* 无向图(邻接多重表)类型定义 */
typedef enum {
unvisit, visit
} VisitIf;
// 顶点类型
typedef char VertexType;
// 边的相关附加信息
typedef struct {
/*
* 注:
* 教材中给出的结构只考虑了无权图,而没考虑有权图(网)。
* 这里为了把“网”的情形也考虑进去,特在附加信息中增加了"权重"属性。
*/
int weight;
} InfoType;
/* 边结点 */
typedef struct EBox {
VisitIf mark; // 访问标记
int ivex; // 该边依附的两个顶点的位置
int jvex; // 该边依附的两个顶点的位置
struct EBox* ilink; // 分别指向依附这两个顶点的下一条边
struct EBox* jlink; // 分别指向依附这两个顶点的下一条边
InfoType* info;
} EBox;
// 每个链表的头结点
typedef struct VexBox {
VertexType data; // 顶点信息
EBox* firstedge; // 指向第一条依附该顶点的边的指针
} VexBox;
/* 图的邻接多重表存储表示类型定义 */
typedef struct {
VexBox adjmulist[MAX_VERTEX_NUM]; // 表头向量
int vexnum, edgenum; // 图/网的顶点数和边数
GraphKind kind; // 图的类型标志
} AMLGraph;
// 边/弧上是否存在附加信息
extern Boolean IncInfo;
/*
* 创建
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL,或path[kind]为""。
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateGraph(AMLGraph* G, char* path[]);
/*
* 构造无向图
*/
static Status CreateUDG(AMLGraph* G);
/*
* 构造无向网
*/
static Status CreateUDN(AMLGraph* G);
/*
* 录入边的相关附加信息
*/
static void Input(AMLGraph G, InfoType** info);
/*
* 查找
*
* 返回顶点u在图/网中的位置
*/
int LocateVex(AMLGraph G, VertexType u);
/*
* 插入顶点
*
* 将指定的顶点v追加到顶点集中,未建立该顶点与其他顶点的关系
*/
Status InsertVex(AMLGraph* G, VertexType v);
/*
* 删除顶点
*
* 从顶点集中删除指定的顶点v,注意需要更新相关的顶点关系
*/
Status DeleteVex(AMLGraph* G, VertexType v);
/*
* 构造一个边结点(仅限内部使用)
*/
static EBox* newEBoxPtr(VisitIf mark, int ivex, int jvex, EBox* ilink, EBox* jlink, InfoType* info);
/*
* 插入边<v, w>
*
* 当前图/网是无向的,且由于特殊的结构,使得插入一条边时只需要增加一对顶点关系,边的数量依然增一。
* 对于图/网来说,可以在可变参数中列出边的附加信息。
*
* 注:此处接收的参数与MGraph有些不一样:网的附加信息中包含了各条边的权值。
*/
Status InsertArc(AMLGraph* G, VertexType v, VertexType w, ...);
/*
* 删除边<v, w>
*/
Status DeleteArc(AMLGraph* G, VertexType v, VertexType w);
/*
* 以图形化形式输出当前结构
*/
void PrintGraph(AMLGraph G);
#endif
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(07.18-07.19 AMLGraph.h AMLGraph.c 07.18-07.19.c)
# 链接公共库
target_link_libraries(07.18-07.19 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
@@ -0,0 +1,6 @@
图类型→2(无向图)
顶点数→6
边数→13
边是否带有其他信息→0
顶点集→【AXBCDE】
边的集合→【A,B】【A,C】【A,D】【B,C】【B,D】【B,E】【C,E】【C,X】【E,A】【E,D】【E,X】【X,A】【X,D】
@@ -0,0 +1,6 @@
图类型→3(无向网)
顶点数→6
边数→13
边是否带有其他信息→1
顶点集→【AXBCDE】
边的集合→【A,B,3】【A,C,8】【A,D,11】【B,C,7】【B,D,4】【B,E,1】【C,E,17】【C,X,3】【E,A,6】【E,D,4】【E,X,2】【X,A,8】【X,D,10】
+78
View File
@@ -0,0 +1,78 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "MGraph.h" //**▲07 图**//
/*
* 判断图G是否可传递
*/
Status Algo_7_20(MGraph G);
int main(int argc, char* argv[]) {
MGraph G;
printf("████████ 创建并输出图...\n");
{
char* path[4];
path[0] = "TestData_DG.txt";
path[1] = "TestData_DN.txt";
path[2] = "TestData_UDG.txt";
path[3] = "TestData_UDN.txt";
CreateGraph(&G, path);
PrintGraph(G);
printf("\n");
}
Algo_7_20(G) ? printf("图G可传递!\n") : printf("图G不可传递!\n");
printf("\n");
return 0;
}
/*
* 判断图G是否可传递
*/
Status Algo_7_20(MGraph G) {
Status trans;
int x, y, z;
int flag; // 不连通的标记
// 对于图,不连通标记是0
if(G.kind == DG || G.kind == UDG) {
flag = 0;
// 对于网,不连通标记是INFINITE
} else if(G.kind == DN || G.kind == UDN) {
flag = INFINITE;
} else {
return ERROR;
}
// 预设为可传递
trans = TRUE;
// 对于V中每个x
for(x = 0; x < G.vexnum; x++) {
// N(x)中每个y
for(y = 0; y < G.vexnum; y++) {
if(G.arcs[x][y].adj != flag) {
// N(y)中不等于x的每个z
for(z = 0; z < G.vexnum; z++) {
if(G.arcs[y][z].adj != flag && z != x) {
// z不在N(x)中
if(G.arcs[x][z].adj == flag) {
// 不可传递
trans = FALSE;
return trans;
}
}
}
}
}
}
return trans;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(07.20 MGraph.h MGraph.c 07.20.c)
# 链接公共库
target_link_libraries(07.20 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+482
View File
@@ -0,0 +1,482 @@
/*=================================
* 图的数组(邻接矩阵)存储表示
*
* 包含算法: 7.1、7.2、7.4、7.5、7.6
==================================*/
#include "MGraph.h" //**▲07 图**//
// 录入数据的源文件;fp为null时,说明需要从控制台录入
static FILE* fp = NULL;
/*
* IncInfo指示该图/网的边/弧上是否存在附加信息。
* 如果其值不为0,则表示无附加信息,否则,表示存在附加信息。
*/
Boolean IncInfo = FALSE;
// 访问标志数组,记录访问过的顶点
static Boolean visited[MAX_VERTEX_NUM];
// 函数变量
static Status (* VisitFunc)(VertexType e);
/*
* ████████ 算法7.1 ████████
*
* 创建图/表
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL,或path[kind]为""。
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateGraph(MGraph* G, char* path[]) {
int readFromConsole; // 是否从控制台读取数据
int kind;
Status flag;
printf("请输入图的类型(0-有向图 │ 1-有向网 │ 2-无向图 │ 3-无向网):");
scanf("%d", &kind);
// 类型不合规
if(kind < 0 || kind > 3) {
return ERROR;
}
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = (path == NULL) || strcmp(path[kind], "") == 0;
// 需要从文件读取
if(readFromConsole) {
(*G).kind = kind; // 记录图/网的类型
} else {
// 打开文件,准备读取测试数据
fp = fopen(path[kind], "r");
if(fp == NULL) {
return ERROR;
}
// 录入图的类型
ReadData(fp, "%d", &((*G).kind));
}
// 随机创建有向图/网或无向图/网的一种
switch((*G).kind) {
case DG:
flag = CreateDG(G);
break;
case DN:
flag = CreateDN(G);
break;
case UDG:
flag = CreateUDG(G);
break;
case UDN:
flag = CreateUDN(G);
break;
default:
flag = ERROR;
break;
}
if(fp != NULL) {
fclose(fp);
fp = NULL;
}
return flag;
}
/*
* 构造有向图
*/
static Status CreateDG(MGraph* G) {
int i, j, k;
ArcCell arcs = {0, NULL}; // 有向图每条边的初始值
VertexType v1, v2;
if(fp == NULL) {
printf("请输入有向图的顶点数:");
scanf("%d", &((*G).vexnum));
printf("请输入有向图的弧数:");
scanf("%d", &((*G).arcnum));
printf("该有向图的弧上是否包含其他附加信息(0-不包含│1-包含):");
scanf("%d", &IncInfo);
// 录入顶点集
printf("请录入 %d 个顶点,不同顶点之间用空格隔开:", (*G).vexnum);
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(stdin);
scanf("%c", &((*G).vexs[i]));
}
} else {
ReadData(fp, "%d", &((*G).vexnum)); // 录入顶点数
ReadData(fp, "%d", &((*G).arcnum)); // 录入弧数
ReadData(fp, "%d", &IncInfo); // 判断弧上是否包含附加信息
// 录入顶点集
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(fp);
ReadData(fp, "%c", &((*G).vexs[i]));
}
}
// 初始化有向图的邻接矩阵
for(i = 0; i < (*G).vexnum; i++) {
for(j = 0; j < (*G).vexnum; j++) {
(*G).arcs[i][j] = arcs;
}
}
// 仅在控制台录入信息时输出此提示
if(fp == NULL && (*G).arcnum != 0) {
printf("请为有向图依次录入 %d 条弧的信息,顶点之间用空格隔开:\n", (*G).arcnum);
}
// 录入弧的信息
for(k = 0; k < (*G).arcnum; k++) {
if(fp == NULL) {
printf("第 %2d 条弧:", k + 1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v2);
} else {
// 跳过空白,寻找下一个可读符号
skipBlank(fp);
ReadData(fp, "%c%c", &v1, &v2);
}
i = LocateVex(*G, v1); // 获取顶点v1在顶点集中的位置
j = LocateVex(*G, v2); // 获取顶点v2在顶点集中的位置
// 将指定的顶点关系设置为1,指示这两个顶点是直接连接的(注:这里没有验证下标是否越界)
(*G).arcs[i][j].adj = 1;
// 如果需要录入弧的其他附加信息
if(IncInfo) {
// 最后录入附加信息
Input(*G, &((*G).arcs[i][j].info));
}
}
// 从文件中读取数据时,最后其实应当判断一下是否读到了足够的信息
return OK;
}
/*
* 构造有向网
*/
static Status CreateDN(MGraph* G) {
int i, j, k;
ArcCell arcs = {INFINITE, NULL}; // 有向网每条弧的初始值
VertexType v1, v2;
VRType w;
if(fp == NULL) {
printf("请输入有向网的顶点数:");
scanf("%d", &((*G).vexnum));
printf("请输入有向网的弧数:");
scanf("%d", &((*G).arcnum));
printf("该有向网的弧上是否包含其他附加信息(0-不包含│1-包含):");
scanf("%d", &IncInfo);
// 录入顶点集
printf("请录入 %d 个顶点,不同顶点之间用空格隔开:", (*G).vexnum);
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(stdin);
scanf("%c", &((*G).vexs[i]));
}
} else {
ReadData(fp, "%d", &((*G).vexnum)); // 录入顶点数
ReadData(fp, "%d", &((*G).arcnum)); // 录入弧数
ReadData(fp, "%d", &IncInfo); // 判断弧上是否包含附加信息
// 录入顶点集
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(fp);
ReadData(fp, "%c", &((*G).vexs[i]));
}
}
// 初始化有向网的邻接矩阵
for(i = 0; i < (*G).vexnum; i++) {
for(j = 0; j < (*G).vexnum; j++) {
(*G).arcs[i][j] = arcs;
}
}
// 仅在控制台录入信息时输出此提示
if(fp == NULL && (*G).arcnum != 0) {
printf("请为有向网依次录入 %d 条弧(带权值)的信息,顶点及权值之间用空格隔开:\n", (*G).arcnum);
}
// 录入弧的信息
for(k = 0; k < (*G).arcnum; k++) {
if(fp == NULL) {
printf("第 %2d 条弧及其权值:", k + 1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v2);
scanf("%d", &w);
} else {
// 跳过空白,寻找下一个可读符号
skipBlank(fp);
ReadData(fp, "%c%c%d", &v1, &v2, &w);
}
i = LocateVex(*G, v1); // 获取顶点v1在顶点集中的位置
j = LocateVex(*G, v2); // 获取顶点v2在顶点集中的位置
// 在指定的顶点关系上记录权值(注:这里没有验证下标是否越界)
(*G).arcs[i][j].adj = w;
// 如果需要录入弧的其他附加信息
if(IncInfo) {
// 最后录入附加信息
Input(*G, &((*G).arcs[i][j].info));
}
}
// 从文件中读取数据时,最后其实应当判断一下是否读到了足够的信息
return OK;
}
/*
* 构造无向图
*/
static Status CreateUDG(MGraph* G) {
int i, j, k;
ArcCell arcs = {0, NULL}; // 无向图每条边的初始值
VertexType v1, v2;
if(fp == NULL) {
printf("请输入无向图的顶点数:");
scanf("%d", &((*G).vexnum));
printf("请输入无向图的边数:");
scanf("%d", &((*G).arcnum));
printf("该无向图的边上是否包含其他附加信息(0-不包含│1-包含):");
scanf("%d", &IncInfo);
// 录入顶点集
printf("请录入 %d 个顶点,不同顶点之间用空格隔开:", (*G).vexnum);
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(stdin);
scanf("%c", &((*G).vexs[i]));
}
} else {
ReadData(fp, "%d", &((*G).vexnum)); // 录入顶点数
ReadData(fp, "%d", &((*G).arcnum)); // 录入边数
ReadData(fp, "%d", &IncInfo); // 判断边上是否包含附加信息
// 录入顶点集
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(fp);
ReadData(fp, "%c", &((*G).vexs[i]));
}
}
// 初始化无向图的邻接矩阵
for(i = 0; i < (*G).vexnum; i++) {
for(j = 0; j < (*G).vexnum; j++) {
(*G).arcs[i][j] = arcs;
}
}
// 仅在控制台录入信息时输出此提示
if(fp == NULL && (*G).arcnum != 0) {
printf("请为无向图依次录入 %d 条边的信息,顶点之间用空格隔开:\n", (*G).arcnum);
}
// 录入边的信息
for(k = 0; k < (*G).arcnum; k++) {
if(fp == NULL) {
printf("第 %2d 条边:", k + 1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v2);
} else {
// 跳过空白,寻找下一个可读符号
skipBlank(fp);
ReadData(fp, "%c%c", &v1, &v2);
}
i = LocateVex(*G, v1); // 获取顶点v1在顶点集中的位置
j = LocateVex(*G, v2); // 获取顶点v2在顶点集中的位置
// 将指定的顶点关系设置为1,指示这两个顶点是直接连接的(注:这里没有验证下标是否越界)
(*G).arcs[i][j].adj = 1;
// 如果需要录入边的其他附加信息
if(IncInfo) {
// 最后录入附加信息
Input(*G, &((*G).arcs[i][j].info));
}
// 填充对称点
(*G).arcs[j][i] = (*G).arcs[i][j];
}
// 从文件中读取数据时,最后其实应当判断一下是否读到了足够的信息
return OK;
}
/*
* ████████ 算法7.2 ████████
*
* 构造无向网
*/
static Status CreateUDN(MGraph* G) {
int i, j, k;
ArcCell arcs = {INFINITE, NULL}; // 无向网每条边的初始值
VertexType v1, v2;
VRType w;
if(fp == NULL) {
printf("请输入无向网的顶点数:");
scanf("%d", &((*G).vexnum));
printf("请输入无向网的边数:");
scanf("%d", &((*G).arcnum));
printf("该无向网的边上是否包含其他附加信息(0-不包含│1-包含):");
scanf("%d", &IncInfo);
// 录入顶点集
printf("请录入 %d 个顶点,不同顶点之间用空格隔开:", (*G).vexnum);
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(stdin);
scanf("%c", &((*G).vexs[i]));
}
} else {
ReadData(fp, "%d", &((*G).vexnum)); // 录入顶点数
ReadData(fp, "%d", &((*G).arcnum)); // 录入边数
ReadData(fp, "%d", &IncInfo); // 判断边上是否包含附加信息
// 录入顶点集
for(i = 0; i < (*G).vexnum; i++) {
// 跳过空白,寻找下一个"可读"符号
skipBlank(fp);
ReadData(fp, "%c", &((*G).vexs[i]));
}
}
// 初始化无向网的邻接矩阵
for(i = 0; i < (*G).vexnum; i++) {
for(j = 0; j < (*G).vexnum; j++) {
(*G).arcs[i][j] = arcs;
}
}
// 仅在控制台录入信息时输出此提示
if(fp == NULL && (*G).arcnum != 0) {
printf("请为无向网依次录入 %d 条边(带权值)的信息,顶点及权值之间用空格隔开:\n", (*G).arcnum);
}
// 录入边的信息
for(k = 0; k < (*G).arcnum; k++) {
if(fp == NULL) {
printf("第 %2d 条边及其权值:", k + 1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v1);
skipBlank(stdin); // 跳过空白,寻找下一个可读符号
scanf("%c", &v2);
scanf("%d", &w);
} else {
// 跳过空白,寻找下一个可读符号
skipBlank(fp);
ReadData(fp, "%c%c%d", &v1, &v2, &w);
}
i = LocateVex(*G, v1); // 获取顶点v1在顶点集中的位置
j = LocateVex(*G, v2); // 获取顶点v2在顶点集中的位置
// 在指定的顶点关系上记录权值(注:这里没有验证下标是否越界)
(*G).arcs[i][j].adj = w;
// 如果需要录入边的其他附加信息
if(IncInfo) {
// 最后录入附加信息
Input(*G, &((*G).arcs[i][j].info));
}
// 填充对称点
(*G).arcs[j][i] = (*G).arcs[i][j];
}
// 从文件中读取数据时,最后其实应当判断一下是否读到了足够的信息
return OK;
}
/*
* 录入边/弧的相关附加信息
*/
static void Input(MGraph G, InfoType** info) {
//录入边/弧的信息,本测试涉及到的边/弧默认无其他附加信息
}
/*
* 查找
*
* 返回顶点u在图/网中的位置
*/
int LocateVex(MGraph G, VertexType u) {
int i;
for(i = 0; i < G.vexnum; i++) {
if(G.vexs[i] == u) {
return i;
}
}
return -1;
}
/*
* 以图形化形式输出当前结构
*
* 注:在图/网中,使用"-"来表示两顶点不直接连通
*/
void PrintGraph(MGraph G) {
int i, j;
if(G.vexnum == 0) {
printf("空图,无需打印!\n");
return;
}
printf("当前图/网包含 %2d 个顶点, %2d 条边/弧...\n", G.vexnum, G.arcnum);
printf(" ");
for(i = 0; i < G.vexnum; i++) {
printf(" %c", G.vexs[i]);
}
printf("\n");
for(i = 0; i < G.vexnum; i++) {
printf("%c ", G.vexs[i]);
for(j = 0; j < G.vexnum; j++) {
if(((G.kind == DG || G.kind == UDG) && G.arcs[i][j].adj == 0) || ((G.kind == DN || G.kind == UDN) && G.arcs[i][j].adj == INFINITE)) {
printf(" -");
} else {
printf("%3d", G.arcs[i][j].adj);
}
}
printf("\n");
}
}
+129
View File
@@ -0,0 +1,129 @@
/*=================================
* 图的数组(邻接矩阵)存储表示
*
* 包含算法: 7.1、7.2、7.4、7.5、7.6
==================================*/
#ifndef MGRAPH_H
#define MGRAPH_H
#include <stdio.h>
#include <limits.h> // 提供宏INT_MAX
#include <string.h> // 提供memset、strcmp 原型
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include "Status.h" //**▲01 绪论**//
/*
* 注:
*
* 通常来讲,无权图被简称为【图】,有权图被简称为【网】。
* 无向图/网中的顶点关系被称为【边】,有向图/网中的顶点关系被称为【弧】,并区分弧头与弧尾。
* 实际表述中,未必会严格遵守以上命名。
*/
/* 宏定义 */
#define INFINITE INT_MAX // 最大值,用来表示网中的两个顶点不直接连接
#define MAX_VERTEX_NUM 26 // 最大顶点个数
// 图的类型
typedef enum {
DG, // 0-有向图
DN, // 1-有向网(带权值)
UDG, // 2-无向图
UDN // 3-无向网(带权值)
} GraphKind;
// 顶点类型
typedef char VertexType;
/*
* 顶点关系类型
*
* 在无权图中,该值通常为0或1,表示两顶点是否直接连通;
* 在有权图中,该值通常为权值。
*/
typedef int VRType;
// 边的相关附加信息
typedef struct {
// 如果有的话,后续会添加相应的属性
} InfoType;
// 边的类型,每条边上可能有附加信息info
typedef struct ArcCell {
VRType adj; // 顶点关系,在有权图跟无权图中的含义不同
InfoType* info; // 边的附加信息,通常忽略
} ArcCell;
/* 图/网的数组(邻接矩阵)存储表示类型定义 */
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量
ArcCell arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵
int vexnum, arcnum; // 图/网的顶点数和弧数
GraphKind kind; // 图的类型标志
} MGraph;
// 边/弧上是否存在附加信息
extern Boolean IncInfo;
/*
* ████████ 算法7.1 ████████
*
* 创建
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL,或path[kind]为""。
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateGraph(MGraph* G, char* path[]);
/*
* 构造有向图
*/
static Status CreateDG(MGraph* G);
/*
* 构造有向网
*/
static Status CreateDN(MGraph* G);
/*
* 构造无向图
*/
static Status CreateUDG(MGraph* G);
/*
* ████████ 算法7.2 ████████
*
* 构造无向网
*/
static Status CreateUDN(MGraph* G);
/*
* 录入边的相关附加信息
*/
static void Input(MGraph G, InfoType** info);
/*
* 查找
*
* 返回顶点u在图/网中的位置
*/
int LocateVex(MGraph G, VertexType u);
/*
* 以图形化形式输出当前结构
*
* 注:在图/网中,使用"-"来表示两顶点不直接连通
*/
void PrintGraph(MGraph G);
#endif
+6
View File
@@ -0,0 +1,6 @@
图类型→0(有向图)
顶点数→5
弧数→10
弧是否带有其他信息→0
顶点集→【ABCDE】
弧的集合→【A,B】【A,C】【A,D】【A,E】【B,A】【B,C】【B,D】【B,E】【C,D】【E,D】
+6
View File
@@ -0,0 +1,6 @@
图类型→1(有向网)
顶点数→5
弧数→10
弧是否带有其他信息→0
顶点集→【ABCDE】
弧的集合→【A,B,5】【A,C,1】【A,D,2】【A,E,6】【B,A,5】【B,C,2】【B,D,8】【B,E,7】【C,D,2】【E,D,3】
@@ -0,0 +1,6 @@
图类型→2(无向图)
顶点数→5
边数→10
边是否带有其他信息→0
顶点集→【ABCDE】
边的集合→【A,B】【A,C】【A,D】【A,E】【B,C】【B,D】【B,E】【C,D】【C,E】【D,E】
@@ -0,0 +1,6 @@
图类型→3(无向网)
顶点数→5
边数→10
边是否带有其他信息→0
顶点集→【ABCDE】
边的集合→【A,B,1】【A,C,3】【A,D,2】【A,E,1】【B,C,5】【B,D,3】【B,E,6】【C,D,8】【C,E,4】【D,E,7】
+75
View File
@@ -0,0 +1,75 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "ALGraph.h" //**▲07 图**//
/*
* 判断图G是否可传递
*/
Status Algo_7_21(ALGraph G);
int main(int argc, char* argv[]) {
ALGraph G;
printf("████████ 创建并输出图...\n");
{
char* path[4];
path[0] = "TestData_DG.txt";
path[1] = "TestData_DN.txt";
path[2] = "TestData_UDG.txt";
path[3] = "TestData_UDN.txt";
CreateGraph(&G, path);
PrintGraph(G);
printf("\n");
}
Algo_7_21(G) ? printf("图G可传递!\n") : printf("图G不可传递!\n");
printf("\n");
return 0;
}
/*
* 判断图G是否可传递
*/
Status Algo_7_21(ALGraph G) {
Status trans;
int x, y, z;
ArcNode* py, * pz, * px;
// 预设为可传递
trans = TRUE;
// 对于V中每个x
for(x = 0; x < G.vexnum; x++) {
// N(x)中每个y
for(py = G.vertices[x].firstarc; py != NULL; py = py->nextarc) {
y = py->adjvex;
for(pz = G.vertices[y].firstarc; pz != NULL; pz = pz->nextarc) {
z = pz->adjvex;
// 排除与x相等的z
if(z != x) {
for(px = G.vertices[x].firstarc; px != NULL; px = px->nextarc) {
if(px->adjvex == z) {
break; // 找到z后及时跳出
}
}
// 如果z不在N(x)中
if(px == NULL) {
trans = FALSE;
return trans;
}
}
}
}
}
return trans;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because it is too large Load Diff
+143
View File
@@ -0,0 +1,143 @@
/*==================
* 图的邻接表存储表示
===================*/
#ifndef ALGRAPH_H
#define ALGRAPH_H
#include <stdio.h>
#include <string.h> // 提供memset、strcmp 原型
#include <stdarg.h> // 提供宏va_list、va_start、va_arg、va_end
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
/*
* 注:
*
* 通常来讲,无权图被简称为【图】,有权图被简称为【网】。
* 无向图/网中的顶点关系被称为【边】,有向图/网中的顶点关系被称为【弧】,并区分弧头与弧尾。
* 实际表述中,未必会严格遵守以上命名。
*
* 当前结构适合存储边/弧比较稀疏的图/网。
*
* ★ 插入边/弧的信息时,这里的实现是按"升序"插入的,这使得插入的弧是按"升序"排列的。
*/
/* 宏定义 */
#define MAX_VERTEX_NUM 26 // 最大顶点个数
// 图的类型
typedef enum {
DG, // 0-有向图
DN, // 1-有向网(带权值)
UDG, // 2-无向图
UDN // 3-无向网(带权值)
} GraphKind;
// 顶点类型
typedef char VertexType;
// 边/弧的相关附加信息
typedef struct {
/*
* 注:
* 教材中给出的结构只考虑了无权图,而没考虑有权图(网)。
* 这里为了把“网”的情形也考虑进去,特在附加信息中增加了"权重"属性。
*/
int weight;
} InfoType;
/* 边/弧结点 */
typedef struct ArcNode {
int adjvex; // 该弧所指向的顶点的位置
struct ArcNode* nextarc; // 指向下一条弧的指针
InfoType* info; // 弧的附加信息,通常忽略
} ArcNode;
// 每个链表的头结点
typedef struct VNode {
VertexType data; // 顶点信息
ArcNode* firstarc; // 指向第一条依附该顶点的弧的指针
} VNode;
/* 图的邻接表存储表示类型定义 */
typedef struct {
VNode vertices[MAX_VERTEX_NUM]; // 邻接表
int vexnum, arcnum; // 图/网的顶点数和弧数
GraphKind kind; // 图的类型标志
} ALGraph;
// 边/弧上是否存在附加信息
extern Boolean IncInfo;
/*
* 创建
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL,或path[kind]为""。
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateGraph(ALGraph* G, char* path[]);
/*
* 构造有向图
*/
static Status CreateDG(ALGraph* G);
/*
* 构造有向网
*/
static Status CreateDN(ALGraph* G);
/*
* 构造无向图
*/
static Status CreateUDG(ALGraph* G);
/*
* 构造无向网
*/
static Status CreateUDN(ALGraph* G);
/*
* 录入边/弧的相关附加信息
*/
static void Input(ALGraph G, InfoType** info);
/*
* 查找
*
* 返回顶点u在图/网中的位置
*/
int LocateVex(ALGraph G, VertexType u);
/*
* 构造一个边/弧结点(仅限内部使用)
*/
static ArcNode* newArcNodePtr(int adjvex, ArcNode* nextarc, InfoType* info);
/*
* 插入边/弧<v, w>
*
* 如果当前图/网是无向的,则插入一条弧需要增加两个顶点关系,但弧的数量只增一。
* 对于图/网来说,可以在可变参数中列出边/弧的附加信息。
*
* 注:此处接收的参数与MGraph有些不一样:网的附加信息中包含了各条边/弧的权值。
*/
Status InsertArc(ALGraph* G, VertexType v, VertexType w, ...);
/*
* 以图形化形式输出当前结构
*/
void PrintGraph(ALGraph G);
#endif
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(07.21 ALGraph.h ALGraph.c 07.21.c)
# 链接公共库
target_link_libraries(07.21 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+6
View File
@@ -0,0 +1,6 @@
图类型→0(有向图)
顶点数→5
弧数→10
弧是否带有其他信息→0
顶点集→【ABCDE】
弧的集合→【A,B】【A,C】【A,D】【A,E】【B,A】【B,C】【B,D】【B,E】【C,D】【E,D】
+6
View File
@@ -0,0 +1,6 @@
图类型→1(有向网)
顶点数→5
弧数→10
弧是否带有其他信息→1
顶点集→【ABCDE】
弧的集合→【A,B,5】【A,C,1】【A,D,2】【A,E,6】【B,A,5】【B,C,2】【B,D,8】【B,E,7】【C,D,2】【E,D,3】
@@ -0,0 +1,6 @@
图类型→2(无向图)
顶点数→5
边数→10
边是否带有其他信息→0
顶点集→【ABCDE】
边的集合→【A,B】【A,C】【A,D】【A,E】【B,C】【B,D】【B,E】【C,D】【C,E】【D,E】
@@ -0,0 +1,6 @@
图类型→3(无向网)
顶点数→5
边数→10
边是否带有其他信息→1
顶点集→【ABCDE】
边的集合→【A,B,1】【A,C,3】【A,D,2】【A,E,1】【B,C,5】【B,D,3】【B,E,6】【C,D,8】【C,E,4】【D,E,7】
@@ -0,0 +1,213 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "ALGraph.h" //**▲07 图**//
// 访问标志数组,记录访问过的顶点
static Boolean visited[MAX_VERTEX_NUM];
/*
* 通过深度优先遍历,输出顶点vi到vj之间的路径
*/
void Algo_7_22(ALGraph G, VertexType vi, VertexType vj);
/*
* 深度优先遍历图G,查找顶点i到顶点j之间的路径存入path
*/
static Status DFS_7_22(ALGraph G, int i, int j, int path[MAX_VERTEX_NUM + 1]);
/*
* 通过广度优先遍历,输出顶点vi到vj之间的路径
*/
void Algo_7_23(ALGraph G, VertexType vi, VertexType vj);
/*
* 广度优先遍历图G,查找顶点i到顶点j之间的路径存入path
*/
static Status BFS_7_23(ALGraph G, int i, int j, int path[MAX_VERTEX_NUM + 1]);
int main(int argc, char* argv[]) {
ALGraph G;
printf("████████ 创建并输出图...\n");
{
char* path[4];
path[0] = "TestData_DG.txt";
path[1] = "";
path[2] = "";
path[3] = "";
CreateGraph(&G, path);
PrintGraph(G);
printf("\n");
}
printf("████████ 题7.22:通过深度优先遍历判断两顶点间是否存在路径...\n");
{
VertexType vi = 'A';
VertexType vj = 'F';
Algo_7_22(G, vi, vj);
printf("\n");
}
printf("████████ 题7.23:通过广度优先遍历判断两顶点间是否存在路径...\n");
{
VertexType vi = 'A';
VertexType vj = 'F';
Algo_7_23(G, vi, vj);
printf("\n");
}
return 0;
}
/*
* 通过深度优先遍历,判断顶点vi到vj之间是否存在路径
*/
void Algo_7_22(ALGraph G, VertexType vi, VertexType vj) {
int i, j, k;
int path[MAX_VERTEX_NUM + 1];
for(k = 0; k < G.vexnum; k++) {
visited[k] = FALSE;
}
i = LocateVex(G, vi);
j = LocateVex(G, vj);
path[0] = 0;
if(DFS_7_22(G, i, j, path) == ERROR) {
printf("%c 到 %c 之间不存在通路!\n", vi, vj);
return;
}
printf("%c 到 %c 之间的通路为:", vi, vj);
for(k = 1; k <= path[0]; k++) {
printf("%c ", GetVex(G, path[k]));
}
printf("\n");
}
/*
* 深度优先遍历图G,查找顶点i到顶点j之间的路径存入path
*/
static Status DFS_7_22(ALGraph G, int i, int j, int path[MAX_VERTEX_NUM + 1]) {
int w;
// 将顶点i加入路径
visited[i] = TRUE;
path[0]++;
path[path[0]] = i;
if(i == j) {
return OK;
}
// 遍历vi所有邻接点
for(w = FirstAdjVex(G, GetVex(G, i)); w >= 0; w = NextAdjVex(G, GetVex(G, i), GetVex(G, w))) {
// 跳过已访问的顶点
if(visited[w]) {
continue;
}
// 递归(深度优先)
if(DFS_7_22(G, w, j, path) == OK) {
return OK;
}
}
// 移除顶点i
visited[i] = FALSE;
path[0]--;
return ERROR;
}
/*
* 通过广度优先遍历,判断顶点vi到vj之间是否存在路径
*/
void Algo_7_23(ALGraph G, VertexType vi, VertexType vj) {
int i, j, k;
int path[MAX_VERTEX_NUM + 1];
for(k = 0; k < G.vexnum; k++) {
visited[k] = FALSE;
}
i = LocateVex(G, vi);
j = LocateVex(G, vj);
path[0] = 0;
if(BFS_7_23(G, i, j, path) == ERROR) {
printf("%c 到 %c 之间不存在通路!\n", vi, vj);
return;
}
printf("%c 到 %c 之间的通路为:", vi, vj);
for(k = 1; k <= path[0]; k++) {
printf("%c ", GetVex(G, path[k]));
}
printf("\n");
}
/*
* 广度优先遍历图G,查找顶点i到顶点j之间的路径存入path
*/
static Status BFS_7_23(ALGraph G, int i, int j, int path[MAX_VERTEX_NUM + 1]) {
int w;
LinkQueue Q;
QElemType e;
// 将顶点i加入路径
visited[i] = TRUE;
path[0]++;
path[path[0]] = i;
if(i == j) {
return OK;
}
// 置空辅助队列
InitQueue(&Q);
// 遍历vi所有邻接点
for(w = FirstAdjVex(G, GetVex(G, i)); w >= 0; w = NextAdjVex(G, GetVex(G, i), GetVex(G, w))) {
// 跳过已访问的顶点
if(visited[w]) {
continue;
}
if(w == j) {
// 将顶点w加入路径
visited[w] = TRUE;
path[0]++;
path[path[0]] = w;
return OK;
}
EnQueue(&Q, w);
}
// 从邻接点出发,继续寻找目标路径
while(!QueueEmpty(Q)) {
DeQueue(&Q, &e);
// 递归(广度优先)
if(BFS_7_23(G, e, j, path) == OK) {
return OK;
}
}
// 移除顶点i
visited[i] = FALSE;
path[0]--;
return ERROR;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Some files were not shown because too many files have changed in this diff Show More