mirror of
https://github.com/kangjianwei/Data-Structure.git
synced 2026-08-18 01:10:14 +08:00
💡 <07 图>习题代码
This commit is contained in:
@@ -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
@@ -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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
弧的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
弧的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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,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);
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
图类型→0(有向图)
|
||||
顶点数→6
|
||||
弧数→14
|
||||
弧是否带有其他信息→0
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
弧的集合→【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
|
||||
弧是否带有其他信息→0
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
弧的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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,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);
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
图类型→0(有向图)
|
||||
顶点数→6
|
||||
弧数→14
|
||||
弧是否带有其他信息→0
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
弧的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
弧的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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
@@ -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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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
|
||||
顶点集→【A,X,B,C,D,E】
|
||||
边的集合→【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,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 |
@@ -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})
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
图类型→0(有向图)
|
||||
顶点数→5
|
||||
弧数→10
|
||||
弧是否带有其他信息→0
|
||||
顶点集→【A,B,C,D,E】
|
||||
弧的集合→【A,B】【A,C】【A,D】【A,E】【B,A】【B,C】【B,D】【B,E】【C,D】【E,D】
|
||||
@@ -0,0 +1,6 @@
|
||||
图类型→1(有向网)
|
||||
顶点数→5
|
||||
弧数→10
|
||||
弧是否带有其他信息→0
|
||||
顶点集→【A,B,C,D,E】
|
||||
弧的集合→【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
|
||||
顶点集→【A,B,C,D,E】
|
||||
边的集合→【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
|
||||
顶点集→【A,B,C,D,E】
|
||||
边的集合→【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,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
@@ -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
|
||||
@@ -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})
|
||||
@@ -0,0 +1,6 @@
|
||||
图类型→0(有向图)
|
||||
顶点数→5
|
||||
弧数→10
|
||||
弧是否带有其他信息→0
|
||||
顶点集→【A,B,C,D,E】
|
||||
弧的集合→【A,B】【A,C】【A,D】【A,E】【B,A】【B,C】【B,D】【B,E】【C,D】【E,D】
|
||||
@@ -0,0 +1,6 @@
|
||||
图类型→1(有向网)
|
||||
顶点数→5
|
||||
弧数→10
|
||||
弧是否带有其他信息→1
|
||||
顶点集→【A,B,C,D,E】
|
||||
弧的集合→【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
|
||||
顶点集→【A,B,C,D,E】
|
||||
边的集合→【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
|
||||
顶点集→【A,B,C,D,E】
|
||||
边的集合→【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
Reference in New Issue
Block a user