结构示意图:
VNode数组(顶点表):
vertices[1] --> [2] --> NULL
↑
ArcNode:表示1连接到2
vertices[2] --> [3] --> [1] --> NULL
↑ ↑
2连3 2连1
vertices[3] --> [2] --> NULL
↑
3连2
定义代码:
//边结点结构体
struct ArcNode { // 表示一条边(h-k)
int adjvex; // 它连接的“邻居”的编号(下标)
int data; // 实际编号(用于输出)
ArcNode *nextarc; // 指向下一条边(邻居)
};
//顶点结构体
struct VNode {
int data; // 顶点本身的编号(1, 2, ..., n)
ArcNode *firstarc; // 指向第一个邻接的边
};
struct ALGraph {
VNode vertices[MVNum]; // 顶点数组
int vexnum; // 顶点数
int arcnum; // 边数
};
总之就是,存两个东西,一个是边结点,一个是顶点。
实例:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_VEX 100 // 最大顶点数
// 边结点定义
typedef struct ArcNode {
int adjvex; // 邻接顶点编号
struct ArcNode* nextarc; // 指向下一个边结点
} ArcNode;
// 顶点结点定义
typedef struct VNode {
int data; // 顶点编号或名称
ArcNode* firstarc; // 指向第一条边
} VNode;
// 图定义
typedef struct {
VNode vertices[MAX_VEX];
int vexnum; // 当前顶点数
int arcnum; // 当前边数
} ALGraph;
// 查找顶点下标
int LocateVex(ALGraph* G, int v) {
for (int i = 0; i < G->vexnum; i++) {
if (G->vertices[i].data == v)
return i;
}
return -1;
}
// 添加顶点
void AddVertex(ALGraph* G, int v) {
G->vertices[G->vexnum].data = v;
G->vertices[G->vexnum].firstarc = NULL;
G->vexnum++;
}
// 添加边
void AddEdge(ALGraph* G, int v1, int v2) {
int i = LocateVex(G, v1);
int j = LocateVex(G, v2);
if (i == -1 || j == -1) return;
ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode));
p1->adjvex = j;
p1->nextarc = G->vertices[i].firstarc;
G->vertices[i].firstarc = p1;
ArcNode* p2 = (ArcNode*)malloc(sizeof(ArcNode));
p2->adjvex = i;
p2->nextarc = G->vertices[j].firstarc;
G->vertices[j].firstarc = p2;
G->arcnum++;
}
// 删除边
void RemoveEdge(ALGraph* G, int v1, int v2) {
int i = LocateVex(G, v1);
int j = LocateVex(G, v2);
if (i == -1 || j == -1) return;
ArcNode **p = &G->vertices[i].firstarc;
while (*p) {
if ((*p)->adjvex == j) {
ArcNode* temp = *p;
*p = (*p)->nextarc;
free(temp);
break;
}
p = &(*p)->nextarc;
}
p = &G->vertices[j].firstarc;
while (*p) {
if ((*p)->adjvex == i) {
ArcNode* temp = *p;
*p = (*p)->nextarc;
free(temp);
break;
}
p = &(*p)->nextarc;
}
G->arcnum--;
}
// 删除顶点
void RemoveVertex(ALGraph* G, int v) {
int i = LocateVex(G, v);
if (i == -1) return;
// 删除所有与该顶点相连的边
while (G->vertices[i].firstarc) {
int adj = G->vertices[i].firstarc->adjvex;
RemoveEdge(G, v, G->vertices[adj].data);
}
// 移动后面的顶点到当前位置
for (int k = i; k < G->vexnum - 1; k++) {
G->vertices[k] = G->vertices[k + 1];
}
G->vexnum--;
// 更新所有邻接点中的编号
for (int m = 0; m < G->vexnum; m++) {
ArcNode* p = G->vertices[m].firstarc;
while (p) {
if (p->adjvex > i)
p->adjvex--;
p = p->nextarc;
}
}
}
// 遍历图(DFS)
bool visited[MAX_VEX];
void DFS(ALGraph* G, int v) {
printf("%d ", G->vertices[v].data);
visited[v] = true;
ArcNode* p = G->vertices[v].firstarc;
while (p) {
if (!visited[p->adjvex])
DFS(G, p->adjvex);
p = p->nextarc;
}
}
// 初始化图
void InitGraph(ALGraph* G) {
G->vexnum = 0;
G->arcnum = 0;
}
// 示例程序
int main() {
ALGraph G;
InitGraph(&G);
// 添加顶点
AddVertex(&G, 1);
AddVertex(&G, 2);
AddVertex(&G, 3);
AddVertex(&G, 4);
// 添加边
AddEdge(&G, 1, 2);
AddEdge(&G, 2, 3);
AddEdge(&G, 3, 4);
printf("DFS遍历:");
for (int i = 0; i < G.vexnum; i++)
visited[i] = false;
DFS(&G, 0); // 从第0个顶点开始
printf("\n");
printf("删除边 (2, 3)\n");
RemoveEdge(&G, 2, 3);
printf("删除顶点 2\n");
RemoveVertex(&G, 2);
printf("DFS遍历:");
for (int i = 0; i < G.vexnum; i++)
visited[i] = false;
DFS(&G, 0);
printf("\n");
return 0;
}
注意:
G->vertices[]
这个数组的下标是从 0 开始的,但你在添加顶点时传入的顶点编号 v
,可能是从 1 开始的
数组下标(实际存储) | 顶点编号(你输入) |
---|---|
vertices[0] | 顶点编号 1 |
vertices[1] | 顶点编号 2 |
vertices[2] | 顶点编号 3 |