[数据结构]图相关算法_邻接矩阵

目录

1.7 图

1.7.1 图的邻接矩阵存储表示

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#include <cstring>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char InfoType;
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
#define OVERFLOW 3
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct {
VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
/* 对带权图,c则为权值类型 */
InfoType *info; /* 该弧相关信息的指针(可无) */
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
AdjMatrix arcs; /* 邻接矩阵 */
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
GraphKind kind; /* 图的种类标志 */
} MGraph;

/* 图的数组(邻接矩阵)存储(存储结构由定义)的基本操作*/
int LocateVex(MGraph G, VertexType u) { /* 初始条件:图G存在,u和G中顶点有相同特征 */
/* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vexs[i]) == 0)
return i;
return -1;
}

Status CreateFAG(MGraph *G) { /* 采用数组(邻接矩阵)表示法,由文件构造没有相关信息的无向图G */
int i, j, k;
char filename[500];
VertexType va, vb;
FILE *graphlist;
printf("请输入数据文件名(f7-1.dat):");
scanf("%s", filename);
graphlist = fopen(filename, "r");
fscanf(graphlist, "%d", &(*G).vexnum);
fscanf(graphlist, "%d", &(*G).arcnum);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
fscanf(graphlist, "%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = 0; /* 图 */
(*G).arcs[i][j].info = NULL; /* 没有相关信息 */
}
for (k = 0; k < (*G).arcnum; ++k) {
fscanf(graphlist, "%s%s", va, vb);
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = (*G).arcs[j][i].adj = 1; /* 无向图 */
}
fclose(graphlist);
(*G).kind = AG;
return OK;
}

Status CreateDG(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造有向图G */
int i, j, k, l, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入有向图G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = 0; /* 图 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条弧的弧尾 弧头(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%*c", va, vb); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = 1; /* 有向图 */
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
l = strlen(s);
if (l) {
info = (char *) malloc((l + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = info; /* 有向 */
}
}
}
(*G).kind = DG;
return OK;
}

Status CreateDN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造有向网G */
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = w; /* 有向网 */
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = info; /* 有向 */
}
}
}
(*G).kind = DN;
return OK;
}

Status CreateAG(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造无向图G */
int i, j, k, l, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = 0; /* 图 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条边的顶点1 顶点2(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%*c", va, vb); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = (*G).arcs[j][i].adj = 1; /* 无向图 */
if (IncInfo) {
printf("请输入该边的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
l = strlen(s);
if (l) {
info = (char *) malloc((l + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = (*G).arcs[j][i].info = info; /* 无向 */
}
}
}
(*G).kind = AG;
return OK;
}

Status CreateAN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造无向网G。*/
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条边的顶点1 顶点2 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = (*G).arcs[j][i].adj = w; /* 无向 */
if (IncInfo) {
printf("请输入该边的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = (*G).arcs[j][i].info = info; /* 无向 */
}
}
}
(*G).kind = AN;
return OK;
}

Status CreateGraph(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造图G。*/
printf("请输入图G的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
scanf("%d", &(*G).kind);
switch ((*G).kind) {
case DG:
return CreateDG(G); /* 构造有向图 */
case DN:
return CreateDN(G); /* 构造有向网 */
case AG:
return CreateAG(G); /* 构造无向图 */
case AN:
return CreateAN(G); /* 构造无向网 */
default:
return ERROR;
}
}

void DestroyGraph(MGraph *G) { /* 初始条件: 图G存在。操作结果: 销毁图G */
int i, j;
if ((*G).kind < 2) /* 有向 */
for (i = 0; i < (*G).vexnum; i++) /* 释放弧的相关信息(如果有的话) */
{
for (j = 0; j < (*G).vexnum; j++)
if ((*G).arcs[i][j].adj == 1 && (*G).kind == 0 ||
(*G).arcs[i][j].adj != INFINITY && (*G).kind == 1) /* 有向图的弧||有向网的弧 */
if ((*G).arcs[i][j].info) /* 有相关信息 */
{
free((*G).arcs[i][j].info);
(*G).arcs[i][j].info = NULL;
}
}
else /* 无向 */
for (i = 0; i < (*G).vexnum; i++) /* 释放边的相关信息(如果有的话) */
for (j = i + 1; j < (*G).vexnum; j++)
if ((*G).arcs[i][j].adj == 1 && (*G).kind == 2 ||
(*G).arcs[i][j].adj != INFINITY && (*G).kind == 3) /* 无向图的边||无向网的边 */
if ((*G).arcs[i][j].info) /* 有相关信息 */
{
free((*G).arcs[i][j].info);
(*G).arcs[i][j].info = (*G).arcs[j][i].info = NULL;
}
(*G).vexnum = 0;
(*G).arcnum = 0;
}

VertexType *GetVex(MGraph G, int v) { /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
if (v >= G.vexnum || v < 0)
exit(ERROR);
return &G.vexs[v];
}

Status PutVex(MGraph *G, VertexType v, VertexType value) { /* 初始条件: 图G存在,v是G中某个顶点。操作结果: 对v赋新值value */
int k;
k = LocateVex(*G, v); /* k为顶点v在图G中的序号 */
if (k < 0)
return ERROR;
strcpy((*G).vexs[k], value);
return OK;
}

int FirstAdjVex(MGraph G, VertexType v) { /* 初始条件: 图G存在,v是G中某个顶点 */
/* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
int i, j = 0, k;
k = LocateVex(G, v); /* k为顶点v在图G中的序号 */
if (G.kind == DN || G.kind == AN) /* 网 */
j = INFINITY;
for (i = 0; i < G.vexnum; i++)
if (G.arcs[k][i].adj != j)
return i;
return -1;
}

int NextAdjVex(MGraph G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
/* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号, */
/* 若w是v的最后一个邻接顶点,则返回-1 */
int i, j = 0, k1, k2;
k1 = LocateVex(G, v); /* k1为顶点v在图G中的序号 */
k2 = LocateVex(G, w); /* k2为顶点w在图G中的序号 */
if (G.kind == DN || G.kind == AN) /* 网 */
j = INFINITY;
for (i = k2 + 1; i < G.vexnum; i++)
if (G.arcs[k1][i].adj != j)
return i;
return -1;
}

void InsertVex(MGraph *G, VertexType v) { /* 初始条件: 图G存在,v和图G中顶点有相同特征 */
/* 操作结果: 在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
int i;
strcpy((*G).vexs[(*G).vexnum], v); /* 构造新顶点向量 */
for (i = 0; i <= (*G).vexnum; i++) {
if ((*G).kind % 2) /* 网 */
{
(*G).arcs[(*G).vexnum][i].adj = INFINITY; /* 初始化该行邻接矩阵的值(无边或弧) */
(*G).arcs[i][(*G).vexnum].adj = INFINITY; /* 初始化该列邻接矩阵的值(无边或弧) */
} else /* 图 */
{
(*G).arcs[(*G).vexnum][i].adj = 0; /* 初始化该行邻接矩阵的值(无边或弧) */
(*G).arcs[i][(*G).vexnum].adj = 0; /* 初始化该列邻接矩阵的值(无边或弧) */
}
(*G).arcs[(*G).vexnum][i].info = NULL; /* 初始化相关信息指针 */
(*G).arcs[i][(*G).vexnum].info = NULL;
}
(*G).vexnum += 1; /* 图G的顶点数加1 */
}

Status DeleteVex(MGraph *G, VertexType v) { /* 初始条件: 图G存在,v是G中某个顶点。操作结果: 删除G中顶点v及其相关的弧 */
int i, j, k;
VRType m = 0;
k = LocateVex(*G, v); /* k为待删除顶点v的序号 */
if (k < 0) /* v不是图G的顶点 */
return ERROR;
if ((*G).kind == DN || (*G).kind == AN) /* 网 */
m = INFINITY;
for (j = 0; j < (*G).vexnum; j++)
if ((*G).arcs[j][k].adj != m) /* 有入弧或边 */
{
if ((*G).arcs[j][k].info) /* 有相关信息 */
free((*G).arcs[j][k].info); /* 释放相关信息 */
(*G).arcnum--; /* 修改弧数 */
}
if ((*G).kind == DG || (*G).kind == DN) /* 有向 */
for (j = 0; j < (*G).vexnum; j++)
if ((*G).arcs[k][j].adj != m) /* 有出弧 */
{
if ((*G).arcs[k][j].info) /* 有相关信息 */
free((*G).arcs[k][j].info); /* 释放相关信息 */
(*G).arcnum--; /* 修改弧数 */
}
for (j = k + 1; j < (*G).vexnum; j++) /* 序号k后面的顶点向量依次前移 */
strcpy((*G).vexs[j - 1], (*G).vexs[j]);
for (i = 0; i < (*G).vexnum; i++)
for (j = k + 1; j < (*G).vexnum; j++)
(*G).arcs[i][j - 1] = (*G).arcs[i][j]; /* 移动待删除顶点之后的矩阵元素 */
for (i = 0; i < (*G).vexnum; i++)
for (j = k + 1; j < (*G).vexnum; j++)
(*G).arcs[j - 1][i] = (*G).arcs[j][i]; /* 移动待删除顶点之下的矩阵元素 */
(*G).vexnum--; /* 更新图的顶点数 */
return OK;
}

Status InsertArc(MGraph *G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v和W是G中两个顶点 */
/* 操作结果: 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v> */
int i, l, v1, w1;
char *info, s[MAX_INFO];
v1 = LocateVex(*G, v); /* 尾 */
w1 = LocateVex(*G, w); /* 头 */
if (v1 < 0 || w1 < 0)
return ERROR;
(*G).arcnum++; /* 弧或边数加1 */
if ((*G).kind % 2) /* 网 */
{
printf("请输入此弧或边的权值: ");
scanf("%d", &(*G).arcs[v1][w1].adj);
} else /* 图 */
(*G).arcs[v1][w1].adj = 1;
printf("是否有该弧或边的相关信息(0:无 1:有): ");
scanf("%d%*c", &i);
if (i) {
printf("请输入该弧或边的相关信息(<%d个字符):", MAX_INFO);
fgets(s, MAX_INFO, stdin);
l = strlen(s);
if (l) {
info = (char *) malloc((l + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[v1][w1].info = info;
}
}
if ((*G).kind > 1) /* 无向 */
{
(*G).arcs[w1][v1].adj = (*G).arcs[v1][w1].adj;
(*G).arcs[w1][v1].info = (*G).arcs[v1][w1].info; /* 指向同一个相关信息 */
}
return OK;
}

Status DeleteArc(MGraph *G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v和w是G中两个顶点 */
/* 操作结果: 在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v> */
int v1, w1;
v1 = LocateVex(*G, v); /* 尾 */
w1 = LocateVex(*G, w); /* 头 */
if (v1 < 0 || w1 < 0) /* v1、w1的值不合法 */
return ERROR;
if ((*G).kind % 2 == 0) /* 图 */
(*G).arcs[v1][w1].adj = 0;
else /* 网 */
(*G).arcs[v1][w1].adj = INFINITY;
if ((*G).arcs[v1][w1].info) /* 有其它信息 */
{
free((*G).arcs[v1][w1].info);
(*G).arcs[v1][w1].info = NULL;
}
if ((*G).kind >= 2) /* 无向,删除对称弧<w,v> */
{
(*G).arcs[w1][v1].adj = (*G).arcs[v1][w1].adj;
(*G).arcs[w1][v1].info = NULL;
}
(*G).arcnum--;
return OK;
}

Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
Status (*VisitFunc)(VertexType); /* 函数变量 */
void DFS(MGraph G, int v) { /* 从第v个顶点出发递归地深度优先遍历图G。*/
VertexType w1, v1;
int w;
visited[v] = TRUE; /* 设置访问标志为TRUE(已访问) */
VisitFunc(G.vexs[v]); /* 访问第v个顶点 */
strcpy(v1, *GetVex(G, v));
for (w = FirstAdjVex(G, v1); w >= 0; w = NextAdjVex(G, v1, strcpy(w1, *GetVex(G, w))))
if (!visited[w])
DFS(G, w); /* 对v的尚未访问的序号为w的邻接顶点递归调用DFS */
}

void DFSTraverse(MGraph G, Status(*Visit)(VertexType)) { /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
/* 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit */
/* 一次且仅一次。一旦Visit()失败,则操作失败 */
int v;
VisitFunc = Visit; /* 使用全局变量VisitFunc,使DFS不必设函数指针参数 */
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE; /* 访问标志数组初始化(未被访问) */
for (v = 0; v < G.vexnum; v++)
if (!visited[v])
DFS(G, v); /* 对尚未访问的顶点调用DFS */
printf("\n");
}

typedef VRType QElemType; /* 队列类型 */
typedef struct QNode {
QElemType data;
struct QNode *next;
} QNode, *QueuePtr;

typedef struct {
QueuePtr front, rear; /* 队头、队尾指针 */
} LinkQueue;

Status InitQueue(LinkQueue *Q) { /* 构造一个空队列Q */
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if (!(*Q).front)
exit(OVERFLOW);
(*Q).front->next = NULL;
return OK;
}

Status QueueEmpty(LinkQueue Q) { /* 若Q为空队列,则返回TRUE,否则返回FALSE */
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}

Status EnQueue(LinkQueue *Q, QElemType e) { /* 插入元素e为Q的新的队尾元素 */
QueuePtr p = (QueuePtr) malloc(sizeof(QNode));
if (!p) /* 存储分配失败 */
exit(OVERFLOW);
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}

Status DeQueue(LinkQueue *Q, QElemType *e) { /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
QueuePtr p;
if ((*Q).front == (*Q).rear)
return ERROR;
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if ((*Q).rear == p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}

void BFSTraverse(MGraph G, Status(*Visit)(VertexType)) { /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
/* 操作结果: 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数 */
/* Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
/* 使用辅助队列Q和访问标志数组visited */
int v, u, w;
VertexType w1, u1;
LinkQueue Q;
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE; /* 置初值 */
InitQueue(&Q); /* 置空的辅助队列Q */
for (v = 0; v < G.vexnum; v++)
if (!visited[v]) /* v尚未访问 */
{
visited[v] = TRUE; /* 设置访问标志为TRUE(已访问) */
Visit(G.vexs[v]);
EnQueue(&Q, v); /* v入队列 */
while (!QueueEmpty(Q)) /* 队列不空 */
{
DeQueue(&Q, &u); /* 队头元素出队并置为u */
strcpy(u1, *GetVex(G, u));
for (w = FirstAdjVex(G, u1); w >= 0; w = NextAdjVex(G, u1, strcpy(w1, *GetVex(G, w))))
if (!visited[w]) /* w为u的尚未访问的邻接顶点的序号 */
{
visited[w] = TRUE;
Visit(G.vexs[w]);
EnQueue(&Q, w);
}
}
}
printf("\n");
}

void Display(MGraph G) { /* 输出邻接矩阵G */
int i, j;
char s[7], s1[3];
switch (G.kind) {
case DG:
strcpy(s, "有向图\0");
strcpy(s1, "弧\0");
break;
case DN:
strcpy(s, "有向网\0");
strcpy(s1, "弧\0");
break;
case AG:
strcpy(s, "无向图\0");
strcpy(s1, "边\0");
break;
case AN:
strcpy(s, "无向网\0");
strcpy(s1, "边\0");
}
printf("%d个顶点%d条%s的%s\n", G.vexnum, G.arcnum, s1, s);
for (i = 0; i < G.vexnum; ++i) /* 输出G.vexs */
printf("G.vexs[%d]=%s\n", i, G.vexs[i]);
printf("G.arcs.adj:\n"); /* 输出G.arcs.adj */
for (i = 0; i < G.vexnum; i++) {
for (j = 0; j < G.vexnum; j++)
printf("%6d", G.arcs[i][j].adj);
printf("\n");
}
printf("G.arcs.info:\n"); /* 输出G.arcs.info */
printf("顶点1(弧尾) 顶点2(弧头) 该%s信息:\n", s1);
if (G.kind < 2) /* 有向 */
for (i = 0; i < G.vexnum; i++)
for (j = 0; j < G.vexnum; j++) {
if (G.arcs[i][j].info)
printf("%5s %11s %s\n", G.vexs[i], G.vexs[j], G.arcs[i][j].info);
}
else /* 无向 */
{
for (i = 0; i < G.vexnum; i++)
for (j = i + 1; j < G.vexnum; j++)
if (G.arcs[i][j].info)
printf("%5s %11s %s\n", G.vexs[i], G.vexs[j], G.arcs[i][j].info);
}
}

Status visit(VertexType i) {
printf("%s ", i);
return OK;
}

int main() {
int i, j, k, n;
VertexType v1, v2;
MGraph g;
CreateFAG(&g);
Display(g);
printf("修改顶点的值,请输入原值 新值: ");
scanf("%s%s", v1, v2);
PutVex(&g, v1, v2);
printf("深度优先搜索的结果:\n");
DFSTraverse(g, visit);
printf("广度优先搜索的结果:\n");
BFSTraverse(g, visit);
printf("删除一条边或弧,请输入待删除边或弧的弧尾 弧头:");
scanf("%s%s", v1, v2);
DeleteArc(&g, v1, v2);
Display(g);
DestroyGraph(&g);
printf("请顺序选择有向图,有向网,无向图,无向网\n");
for (i = 0; i < 4; i++) /* 验证4种情况 */
{
CreateGraph(&g);
Display(g);
printf("插入新顶点,请输入顶点的值: ");
scanf("%s", v1);
InsertVex(&g, v1);
printf("插入与新顶点有关的弧或边,请输入弧或边数: ");
scanf("%d", &n);
for (k = 0; k < n; k++) {
printf("请输入另一顶点的值: ");
scanf("%s", v2);
if (g.kind <= 1) /* 有向 */
{
printf("对于有向图或网,请输入另一顶点的方向(0:弧头 1:弧尾): ");
scanf("%d", &j);
if (j)
InsertArc(&g, v2, v1);
else
InsertArc(&g, v1, v2);
} else /* 无向 */
InsertArc(&g, v1, v2);
}
Display(g);
printf("删除顶点及相关的弧或边,请输入顶点的值: ");
scanf("%s", v1);
DeleteVex(&g, v1);
Display(g);
DestroyGraph(&g);
}
return 0;
}

[数据结构]图相关算法_无向图_02


[数据结构]图相关算法_#define_03


[数据结构]图相关算法_无向图_04


[数据结构]图相关算法_data structure_05


[数据结构]图相关算法_邻接矩阵_06


[数据结构]图相关算法_无向图_07

1.7.2 图的邻接表存储表示

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#include <cstring>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW 3
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 3 /* 顶点字符串的最大长度+1 */
typedef int InfoType; /* 存放网的权值 */
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
/*图的邻接表存储表示 */
#define MAX_VERTEX_NUM 20
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct ArcNode {
int adjvex; /* 该弧所指向的顶点的位置 */
struct ArcNode *nextarc; /* 指向下一条弧的指针 */
InfoType *info; /* 网的权值指针) */
} ArcNode; /* 表结点 */
typedef struct {
VertexType data; /* 顶点信息 */
ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
} VNode, AdjList[MAX_VERTEX_NUM]; /* 头结点 */
typedef struct {
AdjList vertices;
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
int kind; /* 图的种类标志 */
} ALGraph;

/* 图的邻接表存储的基本操作*/
int LocateVex(ALGraph G, VertexType u) { /* 初始条件: 图G存在,u和G中顶点有相同特征 */
/* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vertices[i].data) == 0)
return i;
return -1;
}

Status CreateGraph(ALGraph *G) { /* 采用邻接表存储结构,构造没有相关信息的图G*/
int i, j, k;
int w; /* 权值 */
VertexType va, vb;
ArcNode *p;
printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
scanf("%d", &(*G).kind);
printf("请输入图的顶点数,边数: ");
scanf("%d,%d", &(*G).vexnum, &(*G).arcnum);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
{
scanf("%s", (*G).vertices[i].data);
(*G).vertices[i].firstarc = NULL;
}
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
else /* 图 */
printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
for (k = 0; k < (*G).arcnum; ++k) /* 构造表结点链表 */
{
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
scanf("%d%s%s", &w, va, vb);
else /* 图 */
scanf("%s%s", va, vb);
i = LocateVex(*G, va); /* 弧尾 */
j = LocateVex(*G, vb); /* 弧头 */
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = j;
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w;
} else
p->info = NULL; /* 图 */
p->nextarc = (*G).vertices[i].firstarc; /* 插在表头 */
(*G).vertices[i].firstarc = p;
if ((*G).kind >= 2) /* 无向图或网,产生第二个表结点 */
{
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = i;
if ((*G).kind == 3) /* 无向网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w;
} else
p->info = NULL; /* 无向图 */
p->nextarc = (*G).vertices[j].firstarc; /* 插在表头 */
(*G).vertices[j].firstarc = p;
}
}
return OK;
}

void DestroyGraph(ALGraph *G) { /* 初始条件: 图G存在。操作结果: 销毁图G */
int i;
ArcNode *p, *q;
(*G).vexnum = 0;
(*G).arcnum = 0;
for (i = 0; i < (*G).vexnum; ++i) {
p = (*G).vertices[i].firstarc;
while (p) {
q = p->nextarc;
if ((*G).kind % 2) /* 网 */
free(p->info);
free(p);
p = q;
}
}
}

VertexType *GetVex(ALGraph G, int v) { /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
if (v >= G.vexnum || v < 0)
exit(ERROR);
return &G.vertices[v].data;
}

Status PutVex(ALGraph *G, VertexType v, VertexType value) { /* 初始条件: 图G存在,v是G中某个顶点 */
/* 操作结果: 对v赋新值value */
int i;
i = LocateVex(*G, v);
if (i > -1) /* v是G的顶点 */
{
strcpy((*G).vertices[i].data, value);
return OK;
}
return ERROR;
}

int FirstAdjVex(ALGraph G, VertexType v) { /* 初始条件: 图G存在,v是G中某个顶点 */
/* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
ArcNode *p;
int v1;
v1 = LocateVex(G, v); /* v1为顶点v在图G中的序号 */
p = G.vertices[v1].firstarc;
if (p)
return p->adjvex;
else
return -1;
}

int NextAdjVex(ALGraph G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
/* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
/* 若w是v的最后一个邻接点,则返回-1 */
ArcNode *p;
int v1, w1;
v1 = LocateVex(G, v); /* v1为顶点v在图G中的序号 */
w1 = LocateVex(G, w); /* w1为顶点w在图G中的序号 */
p = G.vertices[v1].firstarc;
while (p && p->adjvex != w1) /* 指针p不空且所指表结点不是w */
p = p->nextarc;
if (!p || !p->nextarc) /* 没找到w或w是最后一个邻接点 */
return -1;
else /* p->adjvex==w */
return p->nextarc->adjvex; /* 返回v的(相对于w的)下一个邻接顶点的序号 */
}

void InsertVex(ALGraph *G, VertexType v) { /* 初始条件: 图G存在,v和图中顶点有相同特征 */
/* 操作结果: 在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
strcpy((*G).vertices[(*G).vexnum].data, v); /* 构造新顶点向量 */
(*G).vertices[(*G).vexnum].firstarc = NULL;
(*G).vexnum++; /* 图G的顶点数加1 */
}

Status DeleteVex(ALGraph *G, VertexType v) { /* 初始条件: 图G存在,v是G中某个顶点 */
/* 操作结果: 删除G中顶点v及其相关的弧 */
int i, j;
ArcNode *p, *q;
j = LocateVex(*G, v); /* j是顶点v的序号 */
if (j < 0) /* v不是图G的顶点 */
return ERROR;
p = (*G).vertices[j].firstarc; /* 删除以v为出度的弧或边 */
while (p) {
q = p;
p = p->nextarc;
if ((*G).kind % 2) /* 网 */
free(q->info);
free(q);
(*G).arcnum--; /* 弧或边数减1 */
}
(*G).vexnum--; /* 顶点数减1 */
for (i = j; i < (*G).vexnum; i++) /* 顶点v后面的顶点前移 */
(*G).vertices[i] = (*G).vertices[i + 1];
for (i = 0; i < (*G).vexnum; i++) /* 删除以v为入度的弧或边且必要时修改表结点的顶点位置值 */
{
p = (*G).vertices[i].firstarc; /* 指向第1条弧或边 */
while (p) /* 有弧 */
{
if (p->adjvex == j) {
if (p == (*G).vertices[i].firstarc) /* 待删结点是第1个结点 */
{
(*G).vertices[i].firstarc = p->nextarc;
if ((*G).kind % 2) /* 网 */
free(p->info);
free(p);
p = (*G).vertices[i].firstarc;
if ((*G).kind < 2) /* 有向 */
(*G).arcnum--; /* 弧或边数减1 */
} else {
q->nextarc = p->nextarc;
if ((*G).kind % 2) /* 网 */
free(p->info);
free(p);
p = q->nextarc;
if ((*G).kind < 2) /* 有向 */
(*G).arcnum--; /* 弧或边数减1 */
}
} else {
if (p->adjvex > j)
p->adjvex--; /* 修改表结点的顶点位置值(序号) */
q = p;
p = p->nextarc;
}
}
}
return OK;
}

Status InsertArc(ALGraph *G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v和w是G中两个顶点 */
/* 操作结果: 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v> */
ArcNode *p;
int w1, i, j;
i = LocateVex(*G, v); /* 弧尾或边的序号 */
j = LocateVex(*G, w); /* 弧头或边的序号 */
if (i < 0 || j < 0)
return ERROR;
(*G).arcnum++; /* 图G的弧或边的数目加1 */
if ((*G).kind % 2) /* 网 */
{
printf("请输入弧(边)%s→%s的权值: ", v, w);
scanf("%d", &w1);
}
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = j;
if ((*G).kind % 2) /* 网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w1;
} else
p->info = NULL;
p->nextarc = (*G).vertices[i].firstarc; /* 插在表头 */
(*G).vertices[i].firstarc = p;
if ((*G).kind >= 2) /* 无向,生成另一个表结点 */
{
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = i;
if ((*G).kind == 3) /* 无向网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w1;
} else
p->info = NULL;
p->nextarc = (*G).vertices[j].firstarc; /* 插在表头 */
(*G).vertices[j].firstarc = p;
}
return OK;
}

Status DeleteArc(ALGraph *G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v和w是G中两个顶点 */
/* 操作结果: 在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v> */
ArcNode *p, *q;
int i, j;
i = LocateVex(*G, v); /* i是顶点v(弧尾)的序号 */
j = LocateVex(*G, w); /* j是顶点w(弧头)的序号 */
if (i < 0 || j < 0 || i == j)
return ERROR;
p = (*G).vertices[i].firstarc; /* p指向顶点v的第一条出弧 */
while (p && p->adjvex != j) /* p不空且所指之弧不是待删除弧<v,w> */
{ /* p指向下一条弧 */
q = p;
p = p->nextarc;
}
if (p && p->adjvex == j) /* 找到弧<v,w> */
{
if (p == (*G).vertices[i].firstarc) /* p所指是第1条弧 */
(*G).vertices[i].firstarc = p->nextarc; /* 指向下一条弧 */
else
q->nextarc = p->nextarc; /* 指向下一条弧 */
if ((*G).kind % 2) /* 网 */
free(p->info);
free(p); /* 释放此结点 */
(*G).arcnum--; /* 弧或边数减1 */
}
if ((*G).kind >= 2) /* 无向,删除对称弧<w,v> */
{
p = (*G).vertices[j].firstarc; /* p指隙サ鉾的第一条出弧 */
while (p && p->adjvex != i) /* p不空且所指之弧不是待删除弧<w,v> */
{ /* p指向下一条弧 */
q = p;
p = p->nextarc;
}
if (p && p->adjvex == i) /* 找到弧<w,v> */
{
if (p == (*G).vertices[j].firstarc) /* p所指是第1条弧 */
(*G).vertices[j].firstarc = p->nextarc; /* 指向下一条弧 */
else
q->nextarc = p->nextarc; /* 指向下一条弧 */
if ((*G).kind == 3) /* 无向网 */
free(p->info);
free(p); /* 释放此结点 */
}
}
return OK;
}

Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
void (*VisitFunc)(char *v); /* 函数变量(全局量) */
void DFS(ALGraph G, int v) { /* 从第v个顶点出发递归地深度优先遍历图G。*/
int w;
VertexType v1, w1;
strcpy(v1, *GetVex(G, v));
visited[v] = TRUE; /* 设置访问标志为TRUE(已访问) */
VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */
for (w = FirstAdjVex(G, v1); w >= 0; w = NextAdjVex(G, v1, strcpy(w1, *GetVex(G, w))))
if (!visited[w])
DFS(G, w); /* 对v的尚未访问的邻接点w递归调用DFS */
}

void DFSTraverse(ALGraph G, void(*Visit)(char *)) { /* 对图G作深度优先遍历。*/
int v;
VisitFunc = Visit; /* 使用全局变量VisitFunc,使DFS不必设函数指针参数 */
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE; /* 访问标志数组初始化 */
for (v = 0; v < G.vexnum; v++)
if (!visited[v])
DFS(G, v); /* 对尚未访问的顶点调用DFS */
printf("\n");
}

typedef int QElemType; /* 队列类型 */
typedef struct QNode {
QElemType data;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct {
QueuePtr front, rear; /* 队头、队尾指针 */
} LinkQueue;

Status InitQueue(LinkQueue *Q) { /* 构造一个空队列Q */
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if (!(*Q).front)
exit(OVERFLOW);
(*Q).front->next = NULL;
return OK;
}

Status QueueEmpty(LinkQueue Q) { /* 若Q为空队列,则返回TRUE,否则返回FALSE */
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}

Status EnQueue(LinkQueue *Q, QElemType e) { /* 插入元素e为Q的新的队尾元素 */
QueuePtr p = (QueuePtr) malloc(sizeof(QNode));
if (!p) /* 存储分配失败 */
exit(OVERFLOW);
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}

Status DeQueue(LinkQueue *Q, QElemType *e) { /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
QueuePtr p;
if ((*Q).front == (*Q).rear)
return ERROR;
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if ((*Q).rear == p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}

void BFSTraverse(ALGraph G, void(*Visit)(char *)) {/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。*/
int v, u, w;
VertexType u1, w1;
LinkQueue Q;
for (v = 0; v < G.vexnum; ++v)
visited[v] = FALSE; /* 置初值 */
InitQueue(&Q); /* 置空的辅助队列Q */
for (v = 0; v < G.vexnum; v++) /* 如果是连通图,只v=0就遍历全图 */
if (!visited[v]) /* v尚未访问 */
{
visited[v] = TRUE;
Visit(G.vertices[v].data);
EnQueue(&Q, v); /* v入队列 */
while (!QueueEmpty(Q)) /* 队列不空 */
{
DeQueue(&Q, &u); /* 队头元素出队并置为u */
strcpy(u1, *GetVex(G, u));
for (w = FirstAdjVex(G, u1); w >= 0; w = NextAdjVex(G, u1, strcpy(w1, *GetVex(G, w))))
if (!visited[w]) /* w为u的尚未访问的邻接顶点 */
{
visited[w] = TRUE;
Visit(G.vertices[w].data);
EnQueue(&Q, w); /* w入队 */
}
}
}
printf("\n");
}

void Display(ALGraph G) { /* 输出图的邻接矩阵G */
int i;
ArcNode *p;
switch (G.kind) {
case DG:
printf("有向图\n");
break;
case DN:
printf("有向网\n");
break;
case AG:
printf("无向图\n");
break;
case AN:
printf("无向网\n");
}
printf("%d个顶点:\n", G.vexnum);
for (i = 0; i < G.vexnum; ++i)
printf("%s ", G.vertices[i].data);
printf("\n%d条弧(边):\n", G.arcnum);
for (i = 0; i < G.vexnum; i++) {
p = G.vertices[i].firstarc;
while (p) {
if (G.kind <= 1) /* 有向 */
{
printf("%s→%s ", G.vertices[i].data, G.vertices[p->adjvex].data);
if (G.kind == DN) /* 网 */
printf(":%d ", *(p->info));
} else /* 无向(避免输出两次) */
{
if (i < p->adjvex) {
printf("%s-%s ", G.vertices[i].data, G.vertices[p->adjvex].data);
if (G.kind == AN) /* 网 */
printf(":%d ", *(p->info));
}
}
p = p->nextarc;
}
printf("\n");
}
}

void print(char *i) {
printf("%s ", i);
}

int main() {
int i, j, k, n;
ALGraph g;
VertexType v1, v2;
printf("请选择有向图\n");
CreateGraph(&g);
Display(g);
printf("删除一条边或弧,请输入待删除边或弧的弧尾 弧头:");
scanf("%s%s", v1, v2);
DeleteArc(&g, v1, v2);
printf("修改顶点的值,请输入原值 新值: ");
scanf("%s%s", v1, v2);
PutVex(&g, v1, v2);
printf("插入新顶点,请输入顶点的值: ");
scanf("%s", v1);
InsertVex(&g, v1);
printf("插入与新顶点有关的弧或边,请输入弧或边数: ");
scanf("%d", &n);
for (k = 0; k < n; k++) {
printf("请输入另一顶点的值: ");
scanf("%s", v2);
printf("对于有向图,请输入另一顶点的方向(0:弧头 1:弧尾): ");
scanf("%d", &j);
if (j)
InsertArc(&g, v2, v1);
else
InsertArc(&g, v1, v2);
}
Display(g);
printf("删除顶点及相关的弧或边,请输入顶点的值: ");
scanf("%s", v1);
DeleteVex(&g, v1);
Display(g);
printf("深度优先搜索的结果:\n");
DFSTraverse(g, print);
printf("广度优先搜索的结果:\n");
BFSTraverse(g, print);
DestroyGraph(&g);
printf("请顺序选择有向网,无向图,无向网\n");
for (i = 0; i < 3; i++) /* 验证另外3种情况 */
{
CreateGraph(&g);
Display(g);
printf("插入新顶点,请输入顶点的值: ");
scanf("%s", v1);
InsertVex(&g, v1);
printf("插入与新顶点有关的弧或边,请输入弧或边数: ");
scanf("%d", &n);
for (k = 0; k < n; k++) {
printf("请输入另一顶点的值: ");
scanf("%s", v2);
if (g.kind <= 1) /* 有向 */
{
printf("对于有向图或网,请输入另一顶点的方向(0:弧头 1:弧尾): ");
scanf("%d", &j);
if (j)
InsertArc(&g, v2, v1);
else
InsertArc(&g, v1, v2);
} else /* 无向 */
InsertArc(&g, v1, v2);
}
Display(g);
printf("删除顶点及相关的弧或边,请输入顶点的值: ");
scanf("%s", v1);
DeleteVex(&g, v1);
Display(g);
DestroyGraph(&g);
}
return 0;
}

[数据结构]图相关算法_邻接矩阵_08


[数据结构]图相关算法_data structure_09


[数据结构]图相关算法_无向图_10


[数据结构]图相关算法_邻接矩阵_11

1.7.3 有向图的十字链表存储表示

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#include <cstring>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW 3
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef char InfoType;
#define MAX_Info 80 /* 信息字符串最大长度+1 */
#define MAX_VERTEX_NAME 3 /* 顶点字符串最大长度+1 */
typedef char VertexType[MAX_VERTEX_NAME];
/* c7-3.h 有向图的十字链表存储表示 */
#define MAX_VERTEX_NUM 20
typedef struct ArcBox {
int tailvex, headvex; /* 该弧的尾和头顶点的位置 */
struct ArcBox *hlink, *tlink; /* 分别为弧头相同和弧尾相同的弧的链域 */
InfoType *info; /* 该弧相关信息的指针(可无) */
} ArcBox; /* 弧结点 */
typedef struct {
VertexType data;
ArcBox *firstin, *firstout; /* 分别指向该顶点第一条入弧和出弧 */
} VexNode; /* 顶点结点 */
typedef struct {
VexNode xlist[MAX_VERTEX_NUM]; /* 表头向量(数组) */
int vexnum, arcnum; /* 有向图的当前顶点数和弧数 */
} OLGraph;

/* bo7-3.c 有向图的十字链表存储(存储结构由c7-3.h定义)的基本函数(15个) */
int LocateVex(OLGraph G, VertexType u) { /* 返回顶点u在有向图G中的位置(序号),如不存在则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i) /* 用循环查找该结点 */
if (!strcmp(G.xlist[i].data, u))
return i;
return -1;
}

Status CreateDG(OLGraph *G) { /* 采用十字链表存储表示,构造有向图G。算法7.3 */
int i, j, k;
int IncInfo;
char str[MAX_Info];
ArcBox *p;
VertexType v1, v2;
printf("请输入有向图的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_VERTEX_NAME);
for (i = 0; i < (*G).vexnum; ++i) { /* 构造表头向量 */
scanf("%s", &(*G).xlist[i].data); /* 输入顶点值 */
(*G).xlist[i].firstin = NULL; /* 初始化指针 */
(*G).xlist[i].firstout = NULL;
}
printf("请输入%d条弧的弧尾和弧头(空格为间隔):\n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) { /* 输入各弧并构造十字链表 */
scanf("%s%s", &v1, &v2);
i = LocateVex(*G, v1); /* 确定v1和v2在G中的位置 */
j = LocateVex(*G, v2);
p = (ArcBox *) malloc(sizeof(ArcBox)); /* 产生弧结点(假定有足够空间) */
p->tailvex = i; /* 对弧结点赋值 */
p->headvex = j;
p->hlink = (*G).xlist[j].firstin; /* 完成在入弧和出弧链表表头的插入 */
p->tlink = (*G).xlist[i].firstout;
(*G).xlist[j].firstin = (*G).xlist[i].firstout = p;
if (IncInfo) { /* 若弧含有相关信息,则输入 */
printf("请输入该弧的相关信息(<%d个字符): ", MAX_Info);
scanf("%s", str);
p->info = (InfoType *) malloc((strlen(str) + 1) * sizeof(InfoType));
strcpy(p->info, str);
} else /* 弧不含有相关信息 */
p->info = NULL;
}
return OK;
}

void DestroyGraph(OLGraph *G) { /* 初始条件: 有向图G存在 */
/* 操作结果: 销毁有向图G */
int j;
ArcBox *p, *q;
for (j = 0; j < (*G).vexnum; j++) /* 对所有顶点 */
{
p = (*G).xlist[j].firstout; /* 仅处理出弧 */
while (p) {
q = p;
p = p->tlink;
if (q->info)
free(q->info);
free(q);
}
}
(*G).arcnum = 0;
(*G).vexnum = 0;
}

VertexType *GetVex(OLGraph G, int v) { /* 初始条件:有向图G存在,v是G中某个顶点的序号。操作结果:返回v的值 */
if (v >= G.vexnum || v < 0)
exit(ERROR);
return &G.xlist[v].data;
}

Status PutVex(OLGraph *G, VertexType v, VertexType value) { /* 初始条件: 有向图G存在,v是G中某个顶点 */
/* 操作结果: 对v赋新值value */
int i;
i = LocateVex(*G, v);
if (i < 0) /* v不是G的顶点 */
return ERROR;
strcpy((*G).xlist[i].data, value);
return OK;
}

int FirstAdjVex(OLGraph G, VertexType v) { /* 初始条件: 有向图G存在,v是G中某个顶点 */
/* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
int i;
ArcBox *p;
i = LocateVex(G, v);
p = G.xlist[i].firstout; /* p指向顶点v的第1个出弧 */
if (p)
return p->headvex;
else
return -1;
}

int NextAdjVex(OLGraph G, VertexType v, VertexType w) { /* 初始条件: 有向图G存在,v是G中某个顶点,w是v的邻接顶点 */
/* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号, */
/* 若w是v的最后一个邻接顶点,则返回-1 */
int i, j;
ArcBox *p;
i = LocateVex(G, v); /* i是顶点v的序号 */
j = LocateVex(G, w); /* j是顶点w的序号 */
p = G.xlist[i].firstout; /* p指向顶点v的第1个出弧 */
while (p && p->headvex != j)
p = p->tlink;
if (p) /* w不是v的最后一个邻接顶点 */
p = p->tlink; /* p指向相对于w的下一个邻接顶点 */
if (p) /* 有下一个邻接顶点 */
return p->headvex;
else
return -1;
}

void InsertVex(OLGraph *G, VertexType v) { /* 初始条件: 有向图G存在,v和有向图G中顶点有相同特征 */
/* 操作结果: 在有向图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
strcpy((*G).xlist[(*G).vexnum].data, v);
(*G).xlist[(*G).vexnum].firstin = (*G).xlist[(*G).vexnum].firstout = NULL;
(*G).vexnum++;
}

Status DeleteVex(OLGraph *G, VertexType v) { /* 初始条件: 有向图G存在,v是G中某个顶点 */
/* 操作结果: 删除G中顶点v及其相关的弧 */
int j, k;
ArcBox *p, *q;
k = LocateVex(*G, v); /* k是顶点v的序号 */
if (k < 0) /* v不是图G的顶点 */
return ERROR;
/* 以下删除顶点v的出弧 */
for (j = 0; j < (*G).vexnum; j++) /* 顶点v的出弧是其它顶点的入弧 */
{
if (j == k)
continue;
p = (*G).xlist[j].firstin; /* 在其它顶点的入弧链表中删除顶点v的出弧 */
while (p)
if (p->tailvex == k && p == (*G).xlist[j].firstin) /* 待删结点为首结点 */
{
(*G).xlist[j].firstin = p->hlink;
break;
} else if (p->tailvex != k) /* 没找到待删结点 */
{
q = p;
p = p->hlink;
} else /* 找到待删结点且不是首结点 */
{
q->hlink = p->hlink;
break;
}
}
p = (*G).xlist[k].firstout; /* 删除与顶点v有关的出弧 */
while (p) {
q = p->tlink; /* q指向p的下一个出弧 */
if (p->info) /* 释放p */
free(p->info);
free(p);
(*G).arcnum--;
p = q;
}
/* 以下删除顶点v的入弧 */
for (j = 0; j < (*G).vexnum; j++) /* 顶点v的入弧是其它顶点的出弧 */
{
if (j == k)
continue;
p = (*G).xlist[j].firstout; /* 在其它顶点的出弧链表中删除顶点v的入弧 */
while (p)
if (p->headvex == k && p == (*G).xlist[j].firstout) /* 待删结点为首结点 */
{
(*G).xlist[j].firstout = p->tlink;
break;
} else if (p->headvex != k) /* 没找到待删结点 */
{
q = p;
p = p->tlink;
} else /* 找到待删结点且不是首结点 */
{
q->tlink = p->tlink;
break;
}
}
p = (*G).xlist[k].firstin; /* 删除与顶点v有关的入弧 */
while (p) {
q = p->hlink; /* q指向p的下一个入弧 */
if (p->info) /* 释放p */
free(p->info);
free(p);
(*G).arcnum--;
p = q;
}
for (j = k + 1; j < (*G).vexnum; j++) /* 序号>k的顶点依次向前移 */
(*G).xlist[j - 1] = (*G).xlist[j];
(*G).vexnum--; /* 顶点数减1 */
for (j = 0; j < (*G).vexnum; j++) /* 结点序号>k的要减1 */
{
p = (*G).xlist[j].firstout; /* 处理出弧 */
while (p) {
if (p->tailvex > k)
p->tailvex--; /* 序号-1 */
if (p->headvex > k)
p->headvex--; /* 序号-1 */
p = p->tlink;
}
}
return OK;
}

Status InsertArc(OLGraph *G, VertexType v, VertexType w) { /* 初始条件: 有向图G存在,v和w是G中两个顶点 */
/* 操作结果: 在G中增添弧<v,w> */
int i, j;
int IncInfo;
char str[MAX_Info];
ArcBox *p;
i = LocateVex(*G, v); /* 弧尾的序号 */
j = LocateVex(*G, w); /* 弧头的序号 */
if (i < 0 || j < 0)
return ERROR;
p = (ArcBox *) malloc(sizeof(ArcBox)); /* 生成新结点 */
p->tailvex = i; /* 给新结点赋值 */
p->headvex = j;
p->hlink = (*G).xlist[j].firstin; /* 插在入弧和出弧的链头 */
p->tlink = (*G).xlist[i].firstout;
(*G).xlist[j].firstin = (*G).xlist[i].firstout = p;
(*G).arcnum++; /* 弧数加1 */
printf("要插入的弧是否含有其它信息(是: 1,否: 0): ");
scanf("%d", &IncInfo);
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_Info);
scanf("%s", str);
p->info = (InfoType *) malloc((strlen(str) + 1) * sizeof(InfoType));
strcpy(p->info, str);
} else
p->info = NULL;
return OK;
}

Status DeleteArc(OLGraph *G, VertexType v, VertexType w) { /* 初始条件: 有向图G存在,v和w是G中两个顶点 */
/* 操作结果: 在G中删除弧<v,w> */
int i, j;
ArcBox *p1, *p2;
i = LocateVex(*G, v); /* 弧尾的序号 */
j = LocateVex(*G, w); /* 弧头的序号 */
if (i < 0 || j < 0 || i == j)
return ERROR;
p2 = (*G).xlist[i].firstout; /* 将弧结点从出弧链表中删去 */
if (p2 && p2->headvex == j) /* 第1个结点为待删除结点 */
(*G).xlist[i].firstout = p2->tlink;
else {
while (p2 && p2->headvex != j) /* 向后找 */
{
p1 = p2;
p2 = p2->tlink;
}
if (p2) /* 没到表尾 */
p1->tlink = p2->tlink;
}
p2 = (*G).xlist[j].firstin; /* 将弧结点从入弧链表中删去 */
if (p2 && p2->tailvex == i)
(*G).xlist[j].firstin = p2->hlink;
else {
while (p2 && p2->tailvex != i) {
p1 = p2;
p2 = p2->hlink;
}
if (p2) /* 没到表尾 */
p1->hlink = p2->hlink;
}
if (p2->info) /* 释放弧结点 */
free(p2->info);
free(p2);
(*G).arcnum--; /* 弧数减1 */
return OK;
}

Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组 */
Status (*VisitFunc)(VertexType); /* 函数变量 */
void DFS(OLGraph G, int i) /* DFSTraverse()调用 */
{
ArcBox *p;
visited[i] = TRUE; /* 访问标志数组置1(已被访问) */
VisitFunc(G.xlist[i].data); /* 遍历第i个顶点 */
p = G.xlist[i].firstout; /* p指向第i个顶点的出度 */
while (p && visited[p->headvex]) /* p没到表尾且该弧的头顶点已被访问 */
p = p->tlink; /* 查找下一个结点 */
if (p && !visited[p->headvex]) /* 该弧的头顶点未被访问 */
DFS(G, p->headvex); /* 递归调用DFS() */
}

void DFSTraverse(OLGraph G, Status(*Visit)(VertexType)) { /* 初始条件: 有向图G存在,v是G中某个顶点,Visit是顶点的应用函数 */
/* 操作结果: 从第1个顶点起,按深度优先递归遍历有向图G,并对每个顶点调用 */
/* 函数Visit一次且仅一次。一旦Visit()失败,则操作失败 */
int i;
for (i = 0; i < G.vexnum; i++)
visited[i] = FALSE; /* 访问标志数组置初值(未被访问) */
VisitFunc = Visit;
for (i = 0; i < G.vexnum; i++) /* 由序号0开始,继续查找未被访问过的顶点 */
if (!visited[i])
DFS(G, i);
printf("\n");
}

typedef int QElemType;
/* c3-3.h 队列的顺序存储结构(可用于循环队列和非循环队列) */
#define MAXQSIZE 5 /* 最大队列长度(对于循环队列,最大队列长度要减1) */
typedef struct {
QElemType *base; /* 初始化的动态分配存储空间 */
int front; /* 头指针,若队列不空,指向队列头元素 */
int rear; /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
} SqQueue;

/* bo3-3.c 循环队列(存储结构由c3-3.h定义)的基本操作(9个) */
Status InitQueue(SqQueue *Q) { /* 构造一个空队列Q */
(*Q).base = (QElemType *) malloc(MAXQSIZE * sizeof(QElemType));
if (!(*Q).base) /* 存储分配失败 */
exit(OVERFLOW);
(*Q).front = (*Q).rear = 0;
return OK;
}

Status QueueEmpty(SqQueue Q) { /* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
if (Q.front == Q.rear) /* 队列空的标志 */
return TRUE;
else
return FALSE;
}

Status EnQueue(SqQueue *Q, QElemType e) { /* 插入元素e为Q的新的队尾元素 */
if (((*Q).rear + 1) % MAXQSIZE == (*Q).front) /* 队列满 */
return ERROR;
(*Q).base[(*Q).rear] = e;
(*Q).rear = ((*Q).rear + 1) % MAXQSIZE;
return OK;
}

Status DeQueue(SqQueue *Q, QElemType *e) { /* 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;否则返回ERROR */
if ((*Q).front == (*Q).rear) /* 队列空 */
return ERROR;
*e = (*Q).base[(*Q).front];
(*Q).front = ((*Q).front + 1) % MAXQSIZE;
return OK;
}

void BFSTraverse(OLGraph G, Status(*Visit)(VertexType)) { /* 初始条件: 有向图G存在,Visit是顶点的应用函数。算法7.6 */
/* 操作结果: 从第1个顶点起,按广度优先非递归遍历有向图G,并对每个顶点调用 */
/* 函数Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
/* 使用辅助队列Q和访问标志数组visited */
int v, u, w;
VertexType u1, w1;
SqQueue Q;
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE;
InitQueue(&Q);
for (v = 0; v < G.vexnum; v++)
if (!visited[v]) {
visited[v] = TRUE;
Visit(G.xlist[v].data);
EnQueue(&Q, v);
while (!QueueEmpty(Q)) {
DeQueue(&Q, &u);
strcpy(u1, *GetVex(G, u));
for (w = FirstAdjVex(G, u1); w >= 0; w = NextAdjVex(G, u1, strcpy(w1, *GetVex(G, w))))
if (!visited[w]) /* w为u的尚未访问的邻接顶点的序号 */
{
visited[w] = TRUE;
Visit(G.xlist[w].data);
EnQueue(&Q, w);
}
}
}
printf("\n");
}

void Display(OLGraph G) { /* 输出有向图G */
int i;
ArcBox *p;
printf("共%d个顶点,%d条弧:\n", G.vexnum, G.arcnum);
for (i = 0; i < G.vexnum; i++) {
printf("顶点%s: 入度: ", G.xlist[i].data);
p = G.xlist[i].firstin;
while (p) {
printf("%s ", G.xlist[p->tailvex].data);
p = p->hlink;
}
printf("出度: ");
p = G.xlist[i].firstout;
while (p) {
printf("%s ", G.xlist[p->headvex].data);
if (p->info) /* 该弧有相关信息 */
printf("弧信息: %s ", p->info);
p = p->tlink;
}
printf("\n");
}
}

Status visit(VertexType v) {
printf("%s ", v);
return OK;
}

int main() {
int j, k, n;
OLGraph g;
VertexType v1, v2;
CreateDG(&g);
Display(g);
printf("修改顶点的值,请输入原值 新值: ");
scanf("%s%s", v1, v2);
PutVex(&g, v1, v2);
printf("插入新顶点,请输入顶点的值: ");
scanf("%s", v1);
InsertVex(&g, v1);
printf("插入与新顶点有关的弧,请输入弧数: ");
scanf("%d", &n);
for (k = 0; k < n; k++) {
printf("请输入另一顶点的值 另一顶点的方向(0:弧头 1:弧尾): ");
scanf("%s%d", v2, &j);
if (j)
InsertArc(&g, v2, v1);
else
InsertArc(&g, v1, v2);
}
Display(g);
printf("删除一条弧,请输入待删除弧的弧尾 弧头:");
scanf("%s%s", v1, v2);
DeleteArc(&g, v1, v2);
Display(g);
printf("删除顶点及相关的弧,请输入顶点的值: ");
scanf("%s", v1);
DeleteVex(&g, v1);
Display(g);
printf("深度优先搜索的结果:\n");
DFSTraverse(g, visit);
printf("广度优先搜索的结果:\n");
BFSTraverse(g, visit);
DestroyGraph(&g);
return 0;
}

[数据结构]图相关算法_#define_12

1.7.4 无向图的邻接多重表存储表示

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#include <cstring>
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW 3
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 3 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 80 /* 相关信息字符串的最大长度+1 */
typedef char InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
#define MAX_VERTEX_NUM 20
typedef enum {
unvisited, visited
} VisitIf;
typedef struct EBox {
VisitIf mark; /* 访问标记 */
int ivex, jvex; /* 该边依附的两个顶点的位置 */
struct EBox *ilink, *jlink; /* 分别指向依附这两个顶点的下一条边 */
InfoType *info; /* 该边信息指针 */
} EBox;
typedef struct {
VertexType data;
EBox *firstedge; /* 指向第一条依附该顶点的边 */
} VexBox;
typedef struct {
VexBox adjmulist[MAX_VERTEX_NUM];
int vexnum, edgenum; /* 无向图的当前顶点数和边数 */
} AMLGraph;

int LocateVex(AMLGraph G, VertexType u) { /* 初始条件: 无向图G存在,u和G中顶点有相同特征 */
/* 操作结果: 若G中存在顶点u,则返回该顶点在无向图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.adjmulist[i].data) == 0)
return i;
return -1;
}

Status CreateGraph(AMLGraph *G) { /* 采用邻接多重表存储结构,构造无向图G */
int i, j, k, l, IncInfo;
char s[MAX_INFO];
VertexType va, vb;
EBox *p;
printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).edgenum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
{
scanf("%s", (*G).adjmulist[i].data);
(*G).adjmulist[i].firstedge = NULL;
}
printf("请顺序输入每条边的两个端点(以空格作为间隔):\n");
for (k = 0; k < (*G).edgenum; ++k) /* 构造表结点链表 */
{
scanf("%s%s%*c", va, vb); /* %*c吃掉回车符 */
i = LocateVex(*G, va); /* 一端 */
j = LocateVex(*G, vb); /* 另一端 */
p = (EBox *) malloc(sizeof(EBox));
p->mark = unvisited; /* 设初值 */
p->ivex = i;
p->jvex = j;
p->info = NULL;
p->ilink = (*G).adjmulist[i].firstedge; /* 插在表头 */
(*G).adjmulist[i].firstedge = p;
p->jlink = (*G).adjmulist[j].firstedge; /* 插在表头 */
(*G).adjmulist[j].firstedge = p;
if (IncInfo) /* 边有相关信息 */
{
printf("请输入该弧的相关信息(<%d个字符):", MAX_INFO);
fgets(s, MAX_INFO, stdin);
l = strlen(s);
if (l) {
p->info = (char *) malloc((l + 1) * sizeof(char));
strcpy(p->info, s);
}
}
}
return OK;
}

VertexType *GetVex(AMLGraph G, int v) { /* 初始条件: 无向图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
if (v >= G.vexnum || v < 0)
exit(ERROR);
return &G.adjmulist[v].data;
}

Status PutVex(AMLGraph *G, VertexType v, VertexType value) { /* 初始条件: 无向图G存在,v是G中某个顶点 */
/* 操作结果: 对v赋新值value */
int i;
i = LocateVex(*G, v);
if (i < 0) /* v不是G的顶点 */
return ERROR;
strcpy((*G).adjmulist[i].data, value);
return OK;
}

int FirstAdjVex(AMLGraph G, VertexType v) { /* 初始条件: 无向图G存在,v是G中某个顶点 */
/* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
int i;
i = LocateVex(G, v);
if (i < 0)
return -1;
if (G.adjmulist[i].firstedge) /* v有邻接顶点 */
if (G.adjmulist[i].firstedge->ivex == i)
return G.adjmulist[i].firstedge->jvex;
else
return G.adjmulist[i].firstedge->ivex;
else
return -1;
}

int NextAdjVex(AMLGraph G, VertexType v, VertexType w) { /* 初始条件: 无向图G存在,v是G中某个顶点,w是v的邻接顶点 */
/* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
/* 若w是v的最后一个邻接点,则返回-1 */
int i, j;
EBox *p;
i = LocateVex(G, v); /* i是顶点v的序号 */
j = LocateVex(G, w); /* j是顶点w的序号 */
if (i < 0 || j < 0) /* v或w不是G的顶点 */
return -1;
p = G.adjmulist[i].firstedge; /* p指向顶点v的第1条边 */
while (p)
if (p->ivex == i && p->jvex != j) /* 不是邻接顶点w(情况1) */
p = p->ilink; /* 找下一个邻接顶点 */
else if (p->jvex == i && p->ivex != j) /* 不是邻接顶点w(情况2) */
p = p->jlink; /* 找下一个邻接顶点 */
else /* 是邻接顶点w */
break;
if (p && p->ivex == i && p->jvex == j) /* 找到邻接顶点w(情况1) */
{
p = p->ilink;
if (p && p->ivex == i)
return p->jvex;
else if (p && p->jvex == i)
return p->ivex;
}
if (p && p->ivex == j && p->jvex == i) /* 找到邻接顶点w(情况2) */
{
p = p->jlink;
if (p && p->ivex == i)
return p->jvex;
else if (p && p->jvex == i)
return p->ivex;
}
return -1;
}

Status InsertVex(AMLGraph *G, VertexType v) { /* 初始条件: 无向图G存在,v和G中顶点有相同特征 */
/* 操作结果: 在G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
if ((*G).vexnum == MAX_VERTEX_NUM) /* 结点已满,不能插入 */
return ERROR;
if (LocateVex(*G, v) >= 0) /* 结点已存在,不能插入 */
return ERROR;
strcpy((*G).adjmulist[(*G).vexnum].data, v);
(*G).adjmulist[(*G).vexnum].firstedge = NULL;
(*G).vexnum++;
return OK;
}

Status DeleteArc(AMLGraph *G, VertexType v, VertexType w) { /* 初始条件: 无向图G存在,v和w是G中两个顶点 */
/* 操作结果: 在G中删除弧<v,w> */
int i, j;
EBox *p, *q;
i = LocateVex(*G, v);
j = LocateVex(*G, w);
if (i < 0 || j < 0 || i == j)
return ERROR; /* 图中没有该点或弧 */
/* 以下使指向待删除边的第1个指针绕过这条边 */
p = (*G).adjmulist[i].firstedge; /* p指向顶点v的第1条边 */
if (p && p->jvex == j) /* 第1条边即为待删除边(情况1) */
(*G).adjmulist[i].firstedge = p->ilink;
else if (p && p->ivex == j) /* 第1条边即为待删除边(情况2) */
(*G).adjmulist[i].firstedge = p->jlink;
else /* 第1条边不是待删除边 */
{
while (p) /* 向后查找弧<v,w> */
{
if (p->ivex == i && p->jvex != j) /* 不是待删除边 */
{
q = p;
p = p->ilink; /* 找下一个邻接顶点 */
} else if (p->jvex == i && p->ivex != j) /* 不是待删除边 */
{
q = p;
p = p->jlink; /* 找下一个邻接顶点 */
} else /* 是邻接顶点w */
break;
}
if (!p) /* 没找到该边 */
return ERROR;
if (p->ivex == i && p->jvex == j) /* 找到弧<v,w>(情况1) */
if (q->ivex == i)
q->ilink = p->ilink;
else
q->jlink = p->ilink;
else if (p->ivex == j && p->jvex == i) /* 找到弧<v,w>(情况2) */
if (q->ivex == i)
q->ilink = p->jlink;
else
q->jlink = p->jlink;
}
/* 以下由另一顶点起找待删除边且删除之 */
p = (*G).adjmulist[j].firstedge; /* p指向顶点w的第1条边 */
if (p->jvex == i) /* 第1条边即为待删除边(情况1) */
{
(*G).adjmulist[j].firstedge = p->ilink;
if (p->info) /* 有相关信息 */
free(p->info);
free(p);
} else if (p->ivex == i) /* 第1条边即为待删除边(情况2) */
{
(*G).adjmulist[j].firstedge = p->jlink;
if (p->info) /* 有相关信息 */
free(p->info);
free(p);
} else /* 第1条边不是待删除边 */
{
while (p) /* 向后查找弧<v,w> */
if (p->ivex == j && p->jvex != i) /* 不是待删除边 */
{
q = p;
p = p->ilink; /* 找下一个邻接顶点 */
} else if (p->jvex == j && p->ivex != i) /* 不是待删除边 */
{
q = p;
p = p->jlink; /* 找下一个邻接顶点 */
} else /* 是邻接顶点v */
break;
if (p->ivex == i && p->jvex == j) /* 找到弧<v,w>(情况1) */
{
if (q->ivex == j)
q->ilink = p->jlink;
else
q->jlink = p->jlink;
if (p->info) /* 有相关信息 */
free(p->info);
free(p);
} else if (p->ivex == j && p->jvex == i) /* 找到弧<v,w>(情况2) */
{
if (q->ivex == j)
q->ilink = p->ilink;
else
q->jlink = p->ilink;
if (p->info) /* 有相关信息 */
free(p->info);
free(p);
}
}
(*G).edgenum--;
return OK;
}

Status DeleteVex(AMLGraph *G, VertexType v) { /* 初始条件: 无向图G存在,v是G中某个顶点 */
/* 操作结果: 删除G中顶点v及其相关的边 */
int i, j;
VertexType w;
EBox *p;
i = LocateVex(*G, v); /* i为待删除顶点的序号 */
if (i < 0)
return ERROR;
for (j = 0; j < (*G).vexnum; j++) /* 删除与顶点v相连的边(如果有的话) */
{
if (j == i)
continue;
strcpy(w, *GetVex(*G, j)); /* w是第j个顶点的值 */
DeleteArc(G, v, w);
}
for (j = i + 1; j < (*G).vexnum; j++) /* 排在顶点v后面的顶点的序号减1 */
(*G).adjmulist[j - 1] = (*G).adjmulist[j];
(*G).vexnum--; /* 顶点数减1 */
for (j = i; j < (*G).vexnum; j++) /* 修改顶点的序号 */
{
p = (*G).adjmulist[j].firstedge;
if (p) {
if (p->ivex == j + 1) {
p->ivex--;
p = p->ilink;
} else {
p->jvex--;
p = p->jlink;
}
}
}
return OK;
}

void DestroyGraph(AMLGraph *G) {
int i;
for (i = (*G).vexnum - 1; i >= 0; i--)
DeleteVex(G, (*G).adjmulist[i].data);
}

Status InsertArc(AMLGraph *G, VertexType v, VertexType w) { /* 初始条件: 无向图G存在,v和W是G中两个顶点 */
/* 操作结果: 在G中增添弧<v,w> */
int i, j, l, IncInfo;
char s[MAX_INFO];
EBox *p;
i = LocateVex(*G, v); /* 一端 */
j = LocateVex(*G, w); /* 另一端 */
if (i < 0 || j < 0)
return ERROR;
p = (EBox *) malloc(sizeof(EBox));
p->mark = unvisited;
p->ivex = i;
p->jvex = j;
p->info = NULL;
p->ilink = (*G).adjmulist[i].firstedge; /* 插在表头 */
(*G).adjmulist[i].firstedge = p;
p->jlink = (*G).adjmulist[j].firstedge; /* 插在表头 */
(*G).adjmulist[j].firstedge = p;
printf("该边是否有相关信息(1:有 0:无): ");
scanf("%d%*c", &IncInfo); /* 吃掉回车符 */
if (IncInfo) /* 边有相关信息 */
{
printf("请输入该边的相关信息(<%d个字符):", MAX_INFO);
fgets(s, MAX_INFO, stdin);
l = strlen(s);
if (l) {
p->info = (char *) malloc((l + 1) * sizeof(char));
strcpy(p->info, s);
}
}
(*G).edgenum++;
return OK;
}

Boolean visite[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
Status (*VisitFunc)(VertexType v);

void DFS(AMLGraph G, int v) {
int j;
EBox *p;
VisitFunc(G.adjmulist[v].data);
visite[v] = TRUE;
p = G.adjmulist[v].firstedge;
while (p) {
j = p->ivex == v ? p->jvex : p->ivex;
if (!visite[j])
DFS(G, j);
p = p->ivex == v ? p->ilink : p->jlink;
}
}

void DFSTraverse(AMLGraph G, Status(*visit)(VertexType)) { /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
/* 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit */
/* 一次且仅一次。一旦Visit()失败,则操作失败 */
int v;
VisitFunc = visit;
for (v = 0; v < G.vexnum; v++)
visite[v] = FALSE;
for (v = 0; v < G.vexnum; v++)
if (!visite[v])
DFS(G, v);
printf("\n");
}

typedef int QElemType; /* 队列类型 */
typedef struct QNode {
QElemType data;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct {
QueuePtr front, rear; /* 队头、队尾指针 */
} LinkQueue;

Status InitQueue(LinkQueue *Q) { /* 构造一个空队列Q */
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if (!(*Q).front)
exit(OVERFLOW);
(*Q).front->next = NULL;
return OK;
}

Status QueueEmpty(LinkQueue Q) { /* 若Q为空队列,则返回TRUE,否则返回FALSE */
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}

Status EnQueue(LinkQueue *Q, QElemType e) { /* 插入元素e为Q的新的队尾元素 */
QueuePtr p = (QueuePtr) malloc(sizeof(QNode));
if (!p) /* 存储分配失败 */
exit(OVERFLOW);
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}

Status DeQueue(LinkQueue *Q, QElemType *e) { /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
QueuePtr p;
if ((*Q).front == (*Q).rear)
return ERROR;
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if ((*Q).rear == p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}

void BFSTraverse(AMLGraph G, Status(*Visit)(VertexType)) { /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
/* 操作结果: 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数 */
/* Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
/* 使用辅助队列Q和访问标志数组visite */
int v, u, w;
VertexType w1, u1;
LinkQueue Q;
for (v = 0; v < G.vexnum; v++)
visite[v] = FALSE; /* 置初值 */
InitQueue(&Q); /* 置空的辅助队列Q */
for (v = 0; v < G.vexnum; v++)
if (!visite[v]) /* v尚未访问 */
{
visite[v] = TRUE; /* 设置访问标志为TRUE(已访问) */
Visit(G.adjmulist[v].data);
EnQueue(&Q, v); /* v入队列 */
while (!QueueEmpty(Q)) /* 队列不空 */
{
DeQueue(&Q, &u); /* 队头元素出队并置为u */
strcpy(u1, *GetVex(G, u));
for (w = FirstAdjVex(G, u1); w >= 0; w = NextAdjVex(G, u1, strcpy(w1, *GetVex(G, w))))
if (!visite[w]) /* w为u的尚未访问的邻接顶点的序号 */
{
visite[w] = TRUE;
Visit(G.adjmulist[w].data);
EnQueue(&Q, w);
}
}
}
printf("\n");
}

void MarkUnvizited(AMLGraph G) { /* 置边的访问标记为未被访问 */
int i;
EBox *p;
for (i = 0; i < G.vexnum; i++) {
p = G.adjmulist[i].firstedge;
while (p) {
p->mark = unvisited;
if (p->ivex == i)
p = p->ilink;
else
p = p->jlink;
}
}
}

void Display(AMLGraph G) { /* 输出无向图的邻接多重表G */
int i;
EBox *p;
MarkUnvizited(G); /* 置边的访问标记为未被访问 */
printf("%d个顶点:\n", G.vexnum);
for (i = 0; i < G.vexnum; ++i)
printf("%s ", G.adjmulist[i].data);
printf("\n%d条边:\n", G.edgenum);
for (i = 0; i < G.vexnum; i++) {
p = G.adjmulist[i].firstedge;
while (p)
if (p->ivex == i) /* 边的i端与该顶点有关 */
{
if (!p->mark) /* 只输出一次 */
{
printf("%s-%s ", G.adjmulist[i].data, G.adjmulist[p->jvex].data);
p->mark = visited;
if (p->info) /* 输出附带信息 */
printf("相关信息: %s ", p->info);
}
p = p->ilink;
} else /* 边的j端与该顶点有关 */
{
if (!p->mark) /* 只输出一次 */
{
printf("%s-%s ", G.adjmulist[p->ivex].data, G.adjmulist[i].data);
p->mark = visited;
if (p->info) /* 输出附带信息 */
printf("相关信息: %s ", p->info);
}
p = p->jlink;
}
printf("\n");
}
}

Status visit(VertexType v) {
printf("%s ", v);
return OK;
}

int main() {
int k, n;
AMLGraph g;
VertexType v1, v2;
CreateGraph(&g);
Display(g);
printf("修改顶点的值,请输入原值 新值: ");
scanf("%s%s", v1, v2);
PutVex(&g, v1, v2);
printf("插入新顶点,请输入顶点的值: ");
scanf("%s", v1);
InsertVex(&g, v1);
printf("插入与新顶点有关的边,请输入边数: ");
scanf("%d", &n);
for (k = 0; k < n; k++) {
printf("请输入另一顶点的值: ");
scanf("%s", v2);
InsertArc(&g, v1, v2);
}
Display(g);
printf("深度优先搜索的结果:\n");
DFSTraverse(g, visit);
printf("广度优先搜索的结果:\n");
BFSTraverse(g, visit);
DestroyGraph(&g);
return 0;
}

运行结果

[数据结构]图相关算法_邻接矩阵_13

1.7.5 最小生成树

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#include <cstring>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int VRType;
typedef char InfoType;
#define MAX_NAME 3 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct {
VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
/* 对带权图,c则为权值类型 */
InfoType *info; /* 该弧相关信息的指针(可无) */
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
AdjMatrix arcs; /* 邻接矩阵 */
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
GraphKind kind; /* 图的种类标志 */
} MGraph;

/*图的数组(邻接矩阵)存储(存储结构由c7-1.h定义)的基本操作*/
int LocateVex(MGraph G, VertexType u) { /* 初始条件:图G存在,u和G中顶点有相同特征 */
/* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vexs[i]) == 0)
return i;
return -1;
}

Status CreateAN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造无向网G。*/
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条边的顶点1 顶点2 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = (*G).arcs[j][i].adj = w; /* 无向 */
if (IncInfo) {
printf("请输入该边的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = (*G).arcs[j][i].info = info; /* 无向 */
}
}
}
(*G).kind = AN;
return OK;
}

typedef struct { /* 记录从顶点集U到V-U的代价最小的边的辅助数组定义 */
VertexType adjvex;
VRType lowcost;
} minside[MAX_VERTEX_NUM];

int minimum(minside SZ, MGraph G) { /* 求closedge.lowcost的最小正值 */
int i = 0, j, k, min;
while (!SZ[i].lowcost)
i++;
min = SZ[i].lowcost; /* 第一个不为0的值 */
k = i;
for (j = i + 1; j < G.vexnum; j++)
if (SZ[j].lowcost > 0)
if (min > SZ[j].lowcost) {
min = SZ[j].lowcost;
k = j;
}
return k;
}

void MiniSpanTree_PRIM(MGraph G, VertexType u) { /* 用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边*/
int i, j, k;
minside closedge;
k = LocateVex(G, u);
for (j = 0; j < G.vexnum; ++j) /* 辅助数组初始化 */
{
if (j != k) {
strcpy(closedge[j].adjvex, u);
closedge[j].lowcost = G.arcs[k][j].adj;
}
}
closedge[k].lowcost = 0; /* 初始,U={u} */
printf("最小代价生成树的各条边为:\n");
for (i = 1; i < G.vexnum; ++i) { /* 选择其余G.vexnum-1个顶点 */
k = minimum(closedge, G); /* 求出T的下一个结点:第K顶点 */
printf("(%s-%s)\n", closedge[k].adjvex, G.vexs[k]); /* 输出生成树的边 */
closedge[k].lowcost = 0; /* 第K顶点并入U集 */
for (j = 0; j < G.vexnum; ++j)
if (G.arcs[k][j].adj < closedge[j].lowcost) { /* 新顶点并入U集后重新选择最小边 */
strcpy(closedge[j].adjvex, G.vexs[k]);
closedge[j].lowcost = G.arcs[k][j].adj;
}
}
}

int main() {
MGraph G;
CreateAN(&G);
MiniSpanTree_PRIM(G, G.vexs[0]);
return 0;
}

[数据结构]图相关算法_#define_14

1.7.6 关节点和重连通分量

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#include <cstring>
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW 3
#define INFEASIBLE -1
/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 2 /* 顶点字符串的最大长度+1 */
typedef int InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
#define MAX_VERTEX_NUM 20
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct ArcNode {
int adjvex; /* 该弧所指向的顶点的位置 */
struct ArcNode *nextarc; /* 指向下一条弧的指针 */
InfoType *info; /* 网的权值指针) */
} ArcNode; /* 表结点 */
typedef struct {
VertexType data; /* 顶点信息 */
ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
} VNode, AdjList[MAX_VERTEX_NUM]; /* 头结点 */
typedef struct {
AdjList vertices;
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
int kind; /* 图的种类标志 */
} ALGraph;

int LocateVex(ALGraph G, VertexType u) { /* 初始条件: 图G存在,u和G中顶点有相同特征 */
/* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vertices[i].data) == 0)
return i;
return -1;
}

Status CreateGraph(ALGraph *G) { /* 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图) */
int i, j, k;
int w; /* 权值 */
VertexType va, vb;
ArcNode *p;
printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
scanf("%d", &(*G).kind);
printf("请输入图的顶点数,边数: ");
scanf("%d,%d", &(*G).vexnum, &(*G).arcnum);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
{
scanf("%s", (*G).vertices[i].data);
(*G).vertices[i].firstarc = NULL;
}
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
else /* 图 */
printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
for (k = 0; k < (*G).arcnum; ++k) /* 构造表结点链表 */
{
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
scanf("%d%s%s", &w, va, vb);
else /* 图 */
scanf("%s%s", va, vb);
i = LocateVex(*G, va); /* 弧尾 */
j = LocateVex(*G, vb); /* 弧头 */
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = j;
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w;
} else
p->info = NULL; /* 图 */
p->nextarc = (*G).vertices[i].firstarc; /* 插在表头 */
(*G).vertices[i].firstarc = p;
if ((*G).kind >= 2) /* 无向图或网,产生第二个表结点 */
{
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = i;
if ((*G).kind == 3) /* 无向网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w;
} else
p->info = NULL; /* 无向图 */
p->nextarc = (*G).vertices[j].firstarc; /* 插在表头 */
(*G).vertices[j].firstarc = p;
}
}
return OK;
}

VertexType *GetVex(ALGraph G, int v) { /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
if (v >= G.vexnum || v < 0)
exit(ERROR);
return &G.vertices[v].data;
}

int FirstAdjVex(ALGraph G, VertexType v) { /* 初始条件: 图G存在,v是G中某个顶点 */
/* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
ArcNode *p;
int v1;
v1 = LocateVex(G, v); /* v1为顶点v在图G中的序号 */
p = G.vertices[v1].firstarc;
if (p)
return p->adjvex;
else
return -1;
}

int NextAdjVex(ALGraph G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
/* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
/* 若w是v的最后一个邻接点,则返回-1 */
ArcNode *p;
int v1, w1;
v1 = LocateVex(G, v); /* v1为顶点v在图G中的序号 */
w1 = LocateVex(G, w); /* w1为顶点w在图G中的序号 */
p = G.vertices[v1].firstarc;
while (p && p->adjvex != w1) /* 指针p不空且所指表结点不是w */
p = p->nextarc;
if (!p || !p->nextarc) /* 没找到w或w是最后一个邻接点 */
return -1;
else /* p->adjvex==w */
return p->nextarc->adjvex; /* 返回v的(相对于w的)下一个邻接顶点的序号 */
}

Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
void (*VisitFunc)(char *v); /* 函数变量(全局量) */
void DFS(ALGraph G, int v) { /* 从第v个顶点出发递归地深度优先遍历图G。*/
int w;
VertexType v1, w1;
strcpy(v1, *GetVex(G, v));
visited[v] = TRUE; /* 设置访问标志为TRUE(已访问) */
VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */
for (w = FirstAdjVex(G, v1); w >= 0; w = NextAdjVex(G, v1, strcpy(w1, *GetVex(G, w))))
if (!visited[w])
DFS(G, w); /* 对v的尚未访问的邻接点w递归调用DFS */
}

typedef int QElemType; /* 队列类型 */
typedef struct QNode {
QElemType data;
struct QNode *next;
} QNode, *QueuePtr;

typedef struct {
QueuePtr front, rear; /* 队头、队尾指针 */
} LinkQueue;

Status InitQueue(LinkQueue *Q) { /* 构造一个空队列Q */
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if (!(*Q).front)
exit(OVERFLOW);
(*Q).front->next = NULL;
return OK;
}

Status QueueEmpty(LinkQueue Q) { /* 若Q为空队列,则返回TRUE,否则返回FALSE */
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}

Status EnQueue(LinkQueue *Q, QElemType e) { /* 插入元素e为Q的新的队尾元素 */
QueuePtr p = (QueuePtr) malloc(sizeof(QNode));
if (!p) /* 存储分配失败 */
exit(OVERFLOW);
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}

Status DeQueue(LinkQueue *Q, QElemType *e) { /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
QueuePtr p;
if ((*Q).front == (*Q).rear)
return ERROR;
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if ((*Q).rear == p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}

void BFSTraverse(ALGraph G, void(*Visit)(char *)) {/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。*/
int v, u, w;
VertexType u1, w1;
LinkQueue Q;
for (v = 0; v < G.vexnum; ++v)
visited[v] = FALSE; /* 置初值 */
InitQueue(&Q); /* 置空的辅助队列Q */
for (v = 0; v < G.vexnum; v++) /* 如果是连通图,只v=0就遍历全图 */
if (!visited[v]) /* v尚未访问 */
{
visited[v] = TRUE;
Visit(G.vertices[v].data);
EnQueue(&Q, v); /* v入队列 */
while (!QueueEmpty(Q)) /* 队列不空 */
{
DeQueue(&Q, &u); /* 队头元素出队并置为u */
strcpy(u1, *GetVex(G, u));
for (w = FirstAdjVex(G, u1); w >= 0; w = NextAdjVex(G, u1, strcpy(w1, *GetVex(G, w))))
if (!visited[w]) /* w为u的尚未访问的邻接顶点 */
{
visited[w] = TRUE;
Visit(G.vertices[w].data);
EnQueue(&Q, w); /* w入队 */
}
}
}
printf("\n");
}

void Display(ALGraph G) { /* 输出图的邻接矩阵G */
int i;
ArcNode *p;
switch (G.kind) {
case DG:
printf("有向图\n");
break;
case DN:
printf("有向网\n");
break;
case AG:
printf("无向图\n");
break;
case AN:
printf("无向网\n");
}
printf("%d个顶点:\n", G.vexnum);
for (i = 0; i < G.vexnum; ++i)
printf("%s ", G.vertices[i].data);
printf("\n%d条弧(边):\n", G.arcnum);
for (i = 0; i < G.vexnum; i++) {
p = G.vertices[i].firstarc;
while (p) {
if (G.kind <= 1) /* 有向 */
{
printf("%s→%s ", G.vertices[i].data, G.vertices[p->adjvex].data);
if (G.kind == DN) /* 网 */
printf(":%d ", *(p->info));
} else /* 无向(避免输出两次) */
{
if (i < p->adjvex) {
printf("%s-%s ", G.vertices[i].data, G.vertices[p->adjvex].data);
if (G.kind == AN) /* 网 */
printf(":%d ", *(p->info));
}
}
p = p->nextarc;
}
printf("\n");
}
}

int count; /* 全局量count对访问计数 */
int low[MAX_VERTEX_NUM];

void DFSArticul(ALGraph G, int v0) { /* 从第v0个顶点出发深度优先遍历图G,查找并输出关节点。*/
int min, w;
ArcNode *p;
visited[v0] = min = ++count; /* v0是第count个访问的顶点 */
for (p = G.vertices[v0].firstarc; p; p = p->nextarc) /* 对v0的每个邻接顶点检查 */
{
w = p->adjvex; /* w为v0的邻接顶点 */
if (visited[w] == 0) /* w未曾访问,是v0的孩子 */
{
DFSArticul(G, w); /* 返回前求得low[w] */
if (low[w] < min)
min = low[w];
if (low[w] >= visited[v0])
printf("%d %s\n", v0, G.vertices[v0].data); /* 关节点 */
} else if (visited[w] < min)
min = visited[w]; /* w已访问,w是v0在生成树上的祖先 */
}
low[v0] = min;
}

void FindArticul(ALGraph G) { /* 连通图G以邻接表作存储结构,查找并输出G上全部关节点。*/
/* 全局量count对访问计数。 */
int i, v;
ArcNode *p;
count = 1;
low[0] = visited[0] = 1; /* 设定邻接表上0号顶点为生成树的根 */
for (i = 1; i < G.vexnum; ++i)
visited[i] = 0; /* 其余顶点尚未访问 */
p = G.vertices[0].firstarc;
v = p->adjvex;
DFSArticul(G, v); /* 从第v顶点出发深度优先查找关节点 */
if (count < G.vexnum) /* 生成树的根有至少两棵子树 */
{
printf("%d %s\n", 0, G.vertices[0].data); /* 根是关节点,输出 */
while (p->nextarc) {
p = p->nextarc;
v = p->adjvex;
if (visited[v] == 0)
DFSArticul(G, v);
}
}
}

int main() {
int i;
ALGraph g;
printf("请选择无向图\n");
CreateGraph(&g);
printf("输出关节点:\n");
FindArticul(g);
printf(" i G.vertices[i].data visited[i] low[i]\n");
for (i = 0; i < g.vexnum; ++i)
printf("%2d %9s %14d %8d\n", i, g.vertices[i].data, visited[i], low[i]);
return 0;
}

[数据结构]图相关算法_邻接矩阵_15

1.7.7 拓扑排序

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#include <cstring>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW 3
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 5 /* 顶点字符串的最大长度 */
typedef int InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
#define MAX_VERTEX_NUM 20
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct ArcNode {
int adjvex; /* 该弧所指向的顶点的位置 */
struct ArcNode *nextarc; /* 指向下一条弧的指针 */
InfoType *info; /* 网的权值指针) */
} ArcNode; /* 表结点 */
typedef struct {
VertexType data; /* 顶点信息 */
ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
} VNode, AdjList[MAX_VERTEX_NUM]; /* 头结点 */
typedef struct {
AdjList vertices;
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
int kind; /* 图的种类标志 */
} ALGraph;

int LocateVex(ALGraph G, VertexType u) { /* 初始条件: 图G存在,u和G中顶点有相同特征 */
/* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vertices[i].data) == 0)
return i;
return -1;
}

Status CreateGraph(ALGraph *G) { /* 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图) */
int i, j, k;
int w; /* 权值 */
VertexType va, vb;
ArcNode *p;
printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
scanf("%d", &(*G).kind);
printf("请输入图的顶点数,边数: ");
scanf("%d,%d", &(*G).vexnum, &(*G).arcnum);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
{
scanf("%s", (*G).vertices[i].data);
(*G).vertices[i].firstarc = NULL;
}
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
else /* 图 */
printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
for (k = 0; k < (*G).arcnum; ++k) /* 构造表结点链表 */
{
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
scanf("%d%s%s", &w, va, vb);
else /* 图 */
scanf("%s%s", va, vb);
i = LocateVex(*G, va); /* 弧尾 */
j = LocateVex(*G, vb); /* 弧头 */
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = j;
if ((*G).kind == 1 || (*G).kind == 3) /* 网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w;
} else
p->info = NULL; /* 图 */
p->nextarc = (*G).vertices[i].firstarc; /* 插在表头 */
(*G).vertices[i].firstarc = p;
if ((*G).kind >= 2) /* 无向图或网,产生第二个表结点 */
{
p = (ArcNode *) malloc(sizeof(ArcNode));
p->adjvex = i;
if ((*G).kind == 3) /* 无向网 */
{
p->info = (int *) malloc(sizeof(int));
*(p->info) = w;
} else
p->info = NULL; /* 无向图 */
p->nextarc = (*G).vertices[j].firstarc; /* 插在表头 */
(*G).vertices[j].firstarc = p;
}
}
return OK;
}

VertexType *GetVex(ALGraph G, int v) { /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
if (v >= G.vexnum || v < 0)
exit(ERROR);
return &G.vertices[v].data;
}

int FirstAdjVex(ALGraph G, VertexType v) { /* 初始条件: 图G存在,v是G中某个顶点 */
/* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
ArcNode *p;
int v1;
v1 = LocateVex(G, v); /* v1为顶点v在图G中的序号 */
p = G.vertices[v1].firstarc;
if (p)
return p->adjvex;
else
return -1;
}

int NextAdjVex(ALGraph G, VertexType v, VertexType w) { /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
/* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
/* 若w是v的最后一个邻接点,则返回-1 */
ArcNode *p;
int v1, w1;
v1 = LocateVex(G, v); /* v1为顶点v在图G中的序号 */
w1 = LocateVex(G, w); /* w1为顶点w在图G中的序号 */
p = G.vertices[v1].firstarc;
while (p && p->adjvex != w1) /* 指针p不空且所指表结点不是w */
p = p->nextarc;
if (!p || !p->nextarc) /* 没找到w或w是最后一个邻接点 */
return -1;
else /* p->adjvex==w */
return p->nextarc->adjvex; /* 返回v的(相对于w的)下一个邻接顶点的序号 */
}

Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
void (*VisitFunc)(char *v); /* 函数变量(全局量) */
void DFS(ALGraph G, int v) { /* 从第v个顶点出发递归地深度优先遍历图G。*/
int w;
VertexType v1, w1;
strcpy(v1, *GetVex(G, v));
visited[v] = TRUE; /* 设置访问标志为TRUE(已访问) */
VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */
for (w = FirstAdjVex(G, v1); w >= 0; w = NextAdjVex(G, v1, strcpy(w1, *GetVex(G, w))))
if (!visited[w])
DFS(G, w); /* 对v的尚未访问的邻接点w递归调用DFS */
}

typedef int QElemType; /* 队列类型 */
typedef struct QNode {
QElemType data;
struct QNode *next;
} QNode, *QueuePtr;

typedef struct {
QueuePtr front, rear; /* 队头、队尾指针 */
} LinkQueue;

Status InitQueue(LinkQueue *Q) { /* 构造一个空队列Q */
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if (!(*Q).front)
exit(OVERFLOW);
(*Q).front->next = NULL;
return OK;
}

Status QueueEmpty(LinkQueue Q) { /* 若Q为空队列,则返回TRUE,否则返回FALSE */
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}

Status EnQueue(LinkQueue *Q, QElemType e) { /* 插入元素e为Q的新的队尾元素 */
QueuePtr p = (QueuePtr) malloc(sizeof(QNode));
if (!p) /* 存储分配失败 */
exit(OVERFLOW);
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}

Status DeQueue(LinkQueue *Q, QElemType *e) { /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
QueuePtr p;
if ((*Q).front == (*Q).rear)
return ERROR;
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if ((*Q).rear == p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}

void BFSTraverse(ALGraph G, void(*Visit)(char *)) {/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。算法7.6 */
int v, u, w;
VertexType u1, w1;
LinkQueue Q;
for (v = 0; v < G.vexnum; ++v)
visited[v] = FALSE; /* 置初值 */
InitQueue(&Q); /* 置空的辅助队列Q */
for (v = 0; v < G.vexnum; v++) /* 如果是连通图,只v=0就遍历全图 */
if (!visited[v]) /* v尚未访问 */
{
visited[v] = TRUE;
Visit(G.vertices[v].data);
EnQueue(&Q, v); /* v入队列 */
while (!QueueEmpty(Q)) /* 队列不空 */
{
DeQueue(&Q, &u); /* 队头元素出队并置为u */
strcpy(u1, *GetVex(G, u));
for (w = FirstAdjVex(G, u1); w >= 0; w = NextAdjVex(G, u1, strcpy(w1, *GetVex(G, w))))
if (!visited[w]) /* w为u的尚未访问的邻接顶点 */
{
visited[w] = TRUE;
Visit(G.vertices[w].data);
EnQueue(&Q, w); /* w入队 */
}
}
}
printf("\n");
}

void Display(ALGraph G) { /* 输出图的邻接矩阵G */
int i;
ArcNode *p;
switch (G.kind) {
case DG:
printf("有向图\n");
break;
case DN:
printf("有向网\n");
break;
case AG:
printf("无向图\n");
break;
case AN:
printf("无向网\n");
}
printf("%d个顶点:\n", G.vexnum);
for (i = 0; i < G.vexnum; ++i)
printf("%s ", G.vertices[i].data);
printf("\n%d条弧(边):\n", G.arcnum);
for (i = 0; i < G.vexnum; i++) {
p = G.vertices[i].firstarc;
while (p) {
if (G.kind <= 1) /* 有向 */
{
printf("%s→%s ", G.vertices[i].data, G.vertices[p->adjvex].data);
if (G.kind == DN) /* 网 */
printf(":%d ", *(p->info));
} else /* 无向(避免输出两次) */
{
if (i < p->adjvex) {
printf("%s-%s ", G.vertices[i].data, G.vertices[p->adjvex].data);
if (G.kind == AN) /* 网 */
printf(":%d ", *(p->info));
}
}
p = p->nextarc;
}
printf("\n");
}
}

void FindInDegree(ALGraph G, int indegree[]) { /* 求顶点的入度*/
int i;
ArcNode *p;
for (i = 0; i < G.vexnum; i++)
indegree[i] = 0; /* 赋初值 */
for (i = 0; i < G.vexnum; i++) {
p = G.vertices[i].firstarc;
while (p) {
indegree[p->adjvex]++;
p = p->nextarc;
}
}
}

typedef int SElemType; /* 栈类型 */
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack {
SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
SElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配的存储空间,以元素为单位 */
} SqStack; /* 顺序栈 */
Status InitStack(SqStack *S) { /* 构造一个空栈S */
(*S).base = (SElemType *) malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}

Status StackEmpty(SqStack S) { /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
if (S.top == S.base)
return TRUE;
else
return FALSE;
}

Status Push(SqStack *S, SElemType e) { /* 插入元素e为新的栈顶元素 */
if ((*S).top - (*S).base >= (*S).stacksize) /* 栈满,追加存储空间 */
{
(*S).base = (SElemType *) realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
*((*S).top)++ = e;
return OK;
}

Status Pop(SqStack *S, SElemType *e) { /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
if ((*S).top == (*S).base)
return ERROR;
*e = *--(*S).top;
return OK;
}

Status TopologicalSort(ALGraph G) { /* 有向图G采用邻接表存储结构。若G无回路,则输出G的顶点的一个拓扑序列并返回OK, */
/* 否则返回ERROR。*/
int i, k, count, indegree[MAX_VERTEX_NUM];
SqStack S;
ArcNode *p;
FindInDegree(G, indegree); /* 对各顶点求入度indegree[0..vernum-1] */
InitStack(&S); /* 初始化栈 */
for (i = 0; i < G.vexnum; ++i) /* 建零入度顶点栈S */
if (!indegree[i])
Push(&S, i); /* 入度为0者进栈 */
count = 0; /* 对输出顶点计数 */
while (!StackEmpty(S)) { /* 栈不空 */
Pop(&S, &i);
printf("%s ", G.vertices[i].data); /* 输出i号顶点并计数 */
++count;
for (p = G.vertices[i].firstarc; p; p = p->nextarc) { /* 对i号顶点的每个邻接点的入度减1 */
k = p->adjvex;
if (!(--indegree[k])) /* 若入度减为0,则入栈 */
Push(&S, k);
}
}
if (count < G.vexnum) {
printf("此有向图有回路\n");
return ERROR;
} else {
printf("为一个拓扑序列。\n");
return OK;
}
}

int main() {
ALGraph f;
printf("请选择有向图\n");
CreateGraph(&f);
Display(f);
TopologicalSort(f);
return 0;
}

运行结果

[数据结构]图相关算法_data structure_16

1.7.8 关键路径

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include <cstring>
#include <cstdlib>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char InfoType;
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct {
VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
/* 对带权图,c则为权值类型 */
InfoType *info; /* 该弧相关信息的指针(可无) */
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
AdjMatrix arcs; /* 邻接矩阵 */
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
GraphKind kind; /* 图的种类标志 */
} MGraph;
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];

int LocateVex(MGraph G, VertexType u) { /* 初始条件:图G存在,u和G中顶点有相同特征 */
/* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vexs[i]) == 0)
return i;
return -1;
}

Status CreateDN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造有向网G */
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = w; /* 有向网 */
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = info; /* 有向 */
}
}
}
(*G).kind = DN;
return OK;
}

void
ShortestPath_DIJ(MGraph G, int v0, PathMatrix *P, ShortPathTable *D) { /* 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度 */
/* D[v]。若P[v][w]为TRUE,则w是从v0到v当前求得最短路径上的顶点。 */
/* final[v]为TRUE当且仅当v∈S*/
int v, w, i, j, min;
Status final[MAX_VERTEX_NUM];
for (v = 0; v < G.vexnum; ++v) {
final[v] = FALSE;
(*D)[v] = G.arcs[v0][v].adj;
for (w = 0; w < G.vexnum; ++w)
(*P)[v][w] = FALSE; /* 设空路径 */
if ((*D)[v] < INFINITY) {
(*P)[v][v0] = TRUE;
(*P)[v][v] = TRUE;
}
}
(*D)[v0] = 0;
final[v0] = TRUE; /* 初始化,v0顶点属于S集 */
for (i = 1; i < G.vexnum; ++i) /* 其余G.vexnum-1个顶点 */
{ /* 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */
min = INFINITY; /* 当前所知离v0顶点的最近距离 */
for (w = 0; w < G.vexnum; ++w)
if (!final[w]) /* w顶点在V-S中 */
if ((*D)[w] < min) {
v = w;
min = (*D)[w];
} /* w顶点离v0顶点更近 */
final[v] = TRUE; /* 离v0顶点最近的v加入S集 */
for (w = 0; w < G.vexnum; ++w) /* 更新当前最短路径及距离 */
{
if (!final[w] && min < INFINITY && G.arcs[v][w].adj < INFINITY &&
(min + G.arcs[v][w].adj < (*D)[w])) { /* 修改D[w]和P[w],w∈V-S */
(*D)[w] = min + G.arcs[v][w].adj;
for (j = 0; j < G.vexnum; ++j)
(*P)[w][j] = (*P)[v][j];
(*P)[w][w] = TRUE;
}
}
}
}

int main() {
int i, j, v0 = 0; /* v0为源点 */
MGraph g;
PathMatrix p;
ShortPathTable d;
CreateDN(&g);
ShortestPath_DIJ(g, v0, &p, &d);
printf("最短路径数组p[i][j]如下:\n");
for (i = 0; i < g.vexnum; ++i) {
for (j = 0; j < g.vexnum; ++j)
printf("%2d", p[i][j]);
printf("\n");
}
printf("%s到各顶点的最短路径长度为:\n", g.vexs[0]);
for (i = 1; i < g.vexnum; ++i)
printf("%s-%s:%d\n", g.vexs[0], g.vexs[i], d[i]);
return 0;
}

运行结果

[数据结构]图相关算法_#define_17

1.7.9 最短路径

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include <cstring>
#include <cstdlib>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char InfoType;
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct {
VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
/* 对带权图,c则为权值类型 */
InfoType *info; /* 该弧相关信息的指针(可无) */
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
AdjMatrix arcs; /* 邻接矩阵 */
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
GraphKind kind; /* 图的种类标志 */
} MGraph;
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];

int LocateVex(MGraph G, VertexType u) { /* 初始条件:图G存在,u和G中顶点有相同特征 */
/* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vexs[i]) == 0)
return i;
return -1;
}

Status CreateDN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造有向网G */
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = w; /* 有向网 */
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = info; /* 有向 */
}
}
}
(*G).kind = DN;
return OK;
}

void
ShortestPath_DIJ(MGraph G, int v0, PathMatrix *P, ShortPathTable *D) { /* 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度 */
/* D[v]。若P[v][w]为TRUE,则w是从v0到v当前求得最短路径上的顶点。 */
/* final[v]为TRUE当且仅当v∈S*/
int v, w, i, j, min;
Status final[MAX_VERTEX_NUM];
for (v = 0; v < G.vexnum; ++v) {
final[v] = FALSE;
(*D)[v] = G.arcs[v0][v].adj;
for (w = 0; w < G.vexnum; ++w)
(*P)[v][w] = FALSE; /* 设空路径 */
if ((*D)[v] < INFINITY) {
(*P)[v][v0] = TRUE;
(*P)[v][v] = TRUE;
}
}
(*D)[v0] = 0;
final[v0] = TRUE; /* 初始化,v0顶点属于S集 */
for (i = 1; i < G.vexnum; ++i) /* 其余G.vexnum-1个顶点 */
{ /* 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */
min = INFINITY; /* 当前所知离v0顶点的最近距离 */
for (w = 0; w < G.vexnum; ++w)
if (!final[w]) /* w顶点在V-S中 */
if ((*D)[w] < min) {
v = w;
min = (*D)[w];
} /* w顶点离v0顶点更近 */
final[v] = TRUE; /* 离v0顶点最近的v加入S集 */
for (w = 0; w < G.vexnum; ++w) /* 更新当前最短路径及距离 */
{
if (!final[w] && min < INFINITY && G.arcs[v][w].adj < INFINITY &&
(min + G.arcs[v][w].adj < (*D)[w])) { /* 修改D[w]和P[w],w∈V-S */
(*D)[w] = min + G.arcs[v][w].adj;
for (j = 0; j < G.vexnum; ++j)
(*P)[w][j] = (*P)[v][j];
(*P)[w][w] = TRUE;
}
}
}
}

int main() {
int i, j, v0 = 0; /* v0为源点 */
MGraph g;
PathMatrix p;
ShortPathTable d;
CreateDN(&g);
ShortestPath_DIJ(g, v0, &p, &d);
printf("最短路径数组p[i][j]如下:\n");
for (i = 0; i < g.vexnum; ++i) {
for (j = 0; j < g.vexnum; ++j)
printf("%2d", p[i][j]);
printf("\n");
}
printf("%s到各顶点的最短路径长度为:\n", g.vexs[0]);
for (i = 1; i < g.vexnum; ++i)
printf("%s-%s:%d\n", g.vexs[0], g.vexs[i], d[i]);
return 0;
}

[数据结构]图相关算法_#define_18

1.7.9 最短路径

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include <cstring>
#include <cstdlib>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char InfoType;
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct {
VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
/* 对带权图,c则为权值类型 */
InfoType *info; /* 该弧相关信息的指针(可无) */
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
AdjMatrix arcs; /* 邻接矩阵 */
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
GraphKind kind; /* 图的种类标志 */
} MGraph;
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];

int LocateVex(MGraph G, VertexType u) { /* 初始条件:图G存在,u和G中顶点有相同特征 */
/* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vexs[i]) == 0)
return i;
return -1;
}

Status CreateDN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造有向网G */
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = w; /* 有向网 */
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = info; /* 有向 */
}
}
}
(*G).kind = DN;
return OK;
}

void
ShortestPath_DIJ(MGraph G, int v0, PathMatrix *P, ShortPathTable *D) { /* 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度 */
/* D[v]。若P[v][w]为TRUE,则w是从v0到v当前求得最短路径上的顶点。 */
/* final[v]为TRUE当且仅当v∈S*/
int v, w, i, j, min;
Status final[MAX_VERTEX_NUM];
for (v = 0; v < G.vexnum; ++v) {
final[v] = FALSE;
(*D)[v] = G.arcs[v0][v].adj;
for (w = 0; w < G.vexnum; ++w)
(*P)[v][w] = FALSE; /* 设空路径 */
if ((*D)[v] < INFINITY) {
(*P)[v][v0] = TRUE;
(*P)[v][v] = TRUE;
}
}
(*D)[v0] = 0;
final[v0] = TRUE; /* 初始化,v0顶点属于S集 */
for (i = 1; i < G.vexnum; ++i) /* 其余G.vexnum-1个顶点 */
{ /* 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */
min = INFINITY; /* 当前所知离v0顶点的最近距离 */
for (w = 0; w < G.vexnum; ++w)
if (!final[w]) /* w顶点在V-S中 */
if ((*D)[w] < min) {
v = w;
min = (*D)[w];
} /* w顶点离v0顶点更近 */
final[v] = TRUE; /* 离v0顶点最近的v加入S集 */
for (w = 0; w < G.vexnum; ++w) /* 更新当前最短路径及距离 */
{
if (!final[w] && min < INFINITY && G.arcs[v][w].adj < INFINITY &&
(min + G.arcs[v][w].adj < (*D)[w])) { /* 修改D[w]和P[w],w∈V-S */
(*D)[w] = min + G.arcs[v][w].adj;
for (j = 0; j < G.vexnum; ++j)
(*P)[w][j] = (*P)[v][j];
(*P)[w][w] = TRUE;
}
}
}
}

int main() {
int i, j, v0 = 0; /* v0为源点 */
MGraph g;
PathMatrix p;
ShortPathTable d;
CreateDN(&g);
ShortestPath_DIJ(g, v0, &p, &d);
printf("最短路径数组p[i][j]如下:\n");
for (i = 0; i < g.vexnum; ++i) {
for (j = 0; j < g.vexnum; ++j)
printf("%2d", p[i][j]);
printf("\n");
}
printf("%s到各顶点的最短路径长度为:\n", g.vexs[0]);
for (i = 1; i < g.vexnum; ++i)
printf("%s-%s:%d\n", g.vexs[0], g.vexs[i], d[i]);
return 0;
}

[数据结构]图相关算法_#define_19

1.7.10 每一对顶点之间的最短路径

#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char VertexType[MAX_NAME];
typedef char InfoType;

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include <cstring>
#include <cstdlib>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum {
DG, DN, AG, AN
} GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct {
VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
/* 对带权图,c则为权值类型 */
InfoType *info; /* 该弧相关信息的指针(可无) */
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
AdjMatrix arcs; /* 邻接矩阵 */
int vexnum, arcnum; /* 图的当前顶点数和弧数 */
GraphKind kind; /* 图的种类标志 */
} MGraph;

int LocateVex(MGraph G, VertexType u) { /* 初始条件:图G存在,u和G中顶点有相同特征 */
/* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
int i;
for (i = 0; i < G.vexnum; ++i)
if (strcmp(u, G.vexs[i]) == 0)
return i;
return -1;
}

Status CreateFAG(MGraph *G) { /* 采用数组(邻接矩阵)表示法,由文件构造没有相关信息的无向图G */
int i, j, k;
char filename[13];
VertexType va, vb;
FILE *graphlist;
printf("请输入数据文件名(f7-1.dat):");
scanf("%s", filename);
graphlist = fopen(filename, "r");
fscanf(graphlist, "%d", &(*G).vexnum);
fscanf(graphlist, "%d", &(*G).arcnum);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
fscanf(graphlist, "%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = 0; /* 图 */
(*G).arcs[i][j].info = NULL; /* 没有相关信息 */
}
for (k = 0; k < (*G).arcnum; ++k) {
fscanf(graphlist, "%s%s", va, vb);
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = (*G).arcs[j][i].adj = 1; /* 无向图 */
}
fclose(graphlist);
(*G).kind = AG;
return OK;
}

Status CreateDG(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造有向图G */
int i, j, k, l, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入有向图G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = 0; /* 图 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条弧的弧尾 弧头(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%*c", va, vb); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = 1; /* 有向图 */
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_INFO);
fgets(s, MAX_INFO, stdin);
l = strlen(s);
if (l) {
info = (char *) malloc((l + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = info; /* 有向 */
}
}
}
(*G).kind = DG;
return OK;
}

Status CreateDN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造有向网G */
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = w; /* 有向网 */
if (IncInfo) {
printf("请输入该弧的相关信息(<%d个字符): ", MAX_INFO);
gets(s);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = info; /* 有向 */
}
}
}
(*G).kind = DN;
return OK;
}

Status CreateAG(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造无向图G */
int i, j, k, l, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = 0; /* 图 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条边的顶点1 顶点2(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%*c", va, vb); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = (*G).arcs[j][i].adj = 1; /* 无向图 */
if (IncInfo) {
printf("请输入该边的相关信息(<%d个字符): ", MAX_INFO);
gets(s);
l = strlen(s);
if (l) {
info = (char *) malloc((l + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = (*G).arcs[j][i].info = info; /* 无向 */
}
}
}
(*G).kind = AG;
return OK;
}

Status CreateAN(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造无向网G。算法7.2 */
int i, j, k, w, IncInfo;
char s[MAX_INFO], *info;
VertexType va, vb;
printf("请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
scanf("%d,%d,%d", &(*G).vexnum, &(*G).arcnum, &IncInfo);
printf("请输入%d个顶点的值(<%d个字符):\n", (*G).vexnum, MAX_NAME);
for (i = 0; i < (*G).vexnum; ++i) /* 构造顶点向量 */
scanf("%s", (*G).vexs[i]);
for (i = 0; i < (*G).vexnum; ++i) /* 初始化邻接矩阵 */
for (j = 0; j < (*G).vexnum; ++j) {
(*G).arcs[i][j].adj = INFINITY; /* 网 */
(*G).arcs[i][j].info = NULL;
}
printf("请输入%d条边的顶点1 顶点2 权值(以空格作为间隔): \n", (*G).arcnum);
for (k = 0; k < (*G).arcnum; ++k) {
scanf("%s%s%d%*c", va, vb, &w); /* %*c吃掉回车符 */
i = LocateVex(*G, va);
j = LocateVex(*G, vb);
(*G).arcs[i][j].adj = (*G).arcs[j][i].adj = w; /* 无向 */
if (IncInfo) {
printf("请输入该边的相关信息(<%d个字符): ", MAX_INFO);
gets(s);
w = strlen(s);
if (w) {
info = (char *) malloc((w + 1) * sizeof(char));
strcpy(info, s);
(*G).arcs[i][j].info = (*G).arcs[j][i].info = info; /* 无向 */
}
}
}
(*G).kind = AN;
return OK;
}

Status CreateGraph(MGraph *G) { /* 采用数组(邻接矩阵)表示法,构造图G。*/
printf("请输入图G的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
scanf("%d", &(*G).kind);
switch ((*G).kind) {
case DG:
return CreateDG(G); /* 构造有向图 */
case DN:
return CreateDN(G); /* 构造有向网 */
case AG:
return CreateAG(G); /* 构造无向图 */
case AN:
return CreateAN(G); /* 构造无向网 */
default:
return ERROR;
}
}

void DestroyGraph(MGraph *G) { /* 初始条件: 图G存在。操作结果: 销毁图G */
int i, j;
if ((*G).kind < 2) /* 有向 */
for (i = 0; i < (*G).vexnum; i++) /* 释放弧的相关信息(如果有的话) */
{
for (j = 0; j < (*G).vexnum; j++)
if ((*G).arcs[i][j].adj == 1 && (*G).kind == 0 ||
(*G).arcs[i][j].adj != INFINITY && (*G).kind == 1) /* 有向图的弧||有向网的弧 */
if ((*G).arcs[i][j].info) /* 有相关信息 */
{
free((*G).arcs[i][j].info);
(*G).arcs[i][j].info = NULL;
}
}
else /* 无向 */
for (i = 0; i < (*G).vexnum; i++) /* 释放边的相关信息(如果有的话) */
for (j = i + 1; j < (*G).vexnum; j++)
if ((*G).arcs[i][j].adj == 1 && (*G).kind == 2 ||
(*G).arcs[i][j].adj != INFINITY && (*G).kind == 3) /* 无向图的边||无向网的边 */
if ((*G).arcs[i][j].info) /* 有相关信息 */
{
free((*G).arcs[i][j].info);
(*G).arcs[i][j].info = (*G).arcs[j][i].info = NULL;
}
(*G).vexnum = 0;
(*G).arcnum = 0;
}

VertexType *GetVex(MGraph G, int v) { /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
if (v >= G.vexnum || v < 0)
exit(ERROR);
return &G.vexs[v];
}

Status PutVex(MGraph *G, VertexType v, VertexType value) { /* 初始条件: 图G存在,v是G中某个顶点。操作结果: 对v赋新值value */
int k;
k = LocateVex(*G, v); /* k为顶点v在图G中的序号 */
if (k < 0)
return ERROR;
strcpy((*G).vexs[k], value);
return OK;
}

typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int DistancMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

void ShortestPath_FLOYD(MGraph G, PathMatrix *P, DistancMatrix *D) { /* 用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其 */
/* 带权长度D[v][w]。若P[v][w][u]为TRUE,则u是从v到w当前求得最短 */
/* 路径上的顶点。算法7.16 */
int u, v, w, i;
for (v = 0; v < G.vexnum; v++) /* 各对结点之间初始已知路径及距离 */
for (w = 0; w < G.vexnum; w++) {
(*D)[v][w] = G.arcs[v][w].adj;
for (u = 0; u < G.vexnum; u++)
(*P)[v][w][u] = FALSE;
if ((*D)[v][w] < INFINITY) /* 从v到w有直接路径 */
{
(*P)[v][w][v] = TRUE;
(*P)[v][w][w] = TRUE;
}
}
for (u = 0; u < G.vexnum; u++)
for (v = 0; v < G.vexnum; v++)
for (w = 0; w < G.vexnum; w++)
if ((*D)[v][u] + (*D)[u][w] < (*D)[v][w]) /* 从v经u到w的一条路径更短 */
{
(*D)[v][w] = (*D)[v][u] + (*D)[u][w];
for (i = 0; i < G.vexnum; i++)
(*P)[v][w][i] = (*P)[v][u][i] || (*P)[u][w][i];
}
}

int main() {
MGraph g;
int i, j, k, l, m, n;
PathMatrix p;
DistancMatrix d;
CreateDN(&g);
for (i = 0; i < g.vexnum; i++)
g.arcs[i][i].adj = 0; /* ShortestPath_FLOYD()要求对角元素值为0 */
printf("邻接矩阵:\n");
for (i = 0; i < g.vexnum; i++) {
for (j = 0; j < g.vexnum; j++)
printf("%11d", g.arcs[i][j]);
printf("\n");
}
ShortestPath_FLOYD(g, &p, &d);
printf("d矩阵:\n");
for (i = 0; i < g.vexnum; i++) {
for (j = 0; j < g.vexnum; j++)
printf("%6d", d[i][j]);
printf("\n");
}
for (i = 0; i < g.vexnum; i++)
for (j = 0; j < g.vexnum; j++)
printf("%s到%s的最短距离为%d\n", g.vexs[i], g.vexs[j], d[i][j]);
printf("p矩阵:\n");
l = strlen(g.vexs[0]); /* 顶点向量字符串的长度 */
for (i = 0; i < g.vexnum; i++) {
for (j = 0; j < g.vexnum; j++) {
if (i != j) {
m = 0; /* 占位空格 */
for (k = 0; k < g.vexnum; k++)
if (p[i][j][k] == 1)
printf("%s", g.vexs[k]);
else
m++;
for (n = 0; n < m * l; n++) /* 输出占位空格 */
printf(" ");
} else
for (k = 0; k < g.vexnum * l; k++) /* 输出占位空格 */
printf(" ");
printf(" "); /* 输出矩阵元素之间的间距 */
}
printf("\n");
}
return 0;
}

运行结果

[数据结构]图相关算法_邻接矩阵_20

Talk is cheap. Show me the code