本次笔记内容:

小白-BG.1 邻接矩阵表示的图结点的结构

小白-BG.2 邻接矩阵表示的图-初始化

小白-BG.3 邻接矩阵表示的图-插入边

小白-BG.4 邻接矩阵表示的图-建立图

小白-BG.5 邻接表表示的图结点的结构

小白-BG.6 邻接表表示的图-建立图


文章目录


用邻接矩阵表示图

结构表示

【数据结构笔记23】C实现:表示图的多种方法(邻接矩阵、邻接表与相关拓展)_插入边

为什么要用结构体将Nv、Ne、WeightType打包?

  • 保证通用性;
  • 保证别人可以理解它们是一体的,并且看得懂。
typedef struct GNode *PtrToGNode;
struct GNode
{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
WeightType G[MaxVertexNum][MaxVertexNum];
DataType Data[MaxVertexNum]; /* 存顶点中可能包含的数据 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */

完整的代码如上。

MGraph初始化

初始化一个有VertexNum个顶点但是没有边的图。

typedef int Vertex; /* 用顶点下标表示顶点,为整形 */
MGraph CreateGraph(int VertexNum)
{
Vertex V, W;
MGraph Graph;
Graph = (MGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
/* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */
for (V = 0; V < Graph->Nv; V++)
for (W = 0; W < Graph->Nv; W++)
Graph->G[V][W] = 0; /* 或INFINITY */
return Graph;
}

向MGraph中插入边

typedef struct ENode *PtrToENode;
struct ENode
{
Vertex V1, V2; /* 有向边<V1, V2> */
WeightType Weight; /* 权重 */
};
typedef PtrToENode Edge;

void InsertEdge(MGraph Graph, Edge E)
{
/* 插入边<V1, V2> */
Graph->G[E->V1][E->V2] = E->Weight;
/* 若是无向图,还要插入边<V2, V1> */
Graph->G[E->V2][E->V1] = E->Weight;
}

完整地建立一个MGraph

输入格式:


Nv Ne
V1 V2 Weight


MGraph BuildGraph()
{
MGraph Graph;
Edge E;
Vertex V;
int Nv, i;

MGraph Graph;
scanf("%d", &Nv);
Graph = CreateGraph(Nv);
scanf("%d", &(Graph->Ne));
if (Graph->Ne != 0)
{
E = (Edge)malloc(sizeof(struct ENode));
for (i = 0; i < Graph->Ne; i++)
{
scanf("%d %d %d",
&E->V1, &E->V2, &E->Weight);
InsertEdge(Graph, E);
}
}
/* 如果顶点有数据的话,读入数据 */
for (V = 0; V < Graph->Nv; V++)
scanf(" %c", &(Graph->Data[V]));

return Graph;
}

如果不想这么“麻烦”,则可如下,将Graph声明为全局变量。

int G[MAXN][MAXN], Nv, Ne;
void BuildGraph()
{
int i, j, v1, v2, w;
scanf("%d", &Nv);
/* CreateGraph */
for (i = 0; i < Nv; i++)
for (j = 0; j < Nv; j++)
G[i][j] = 0; /* 或INFINITY */
scanf("%d", &Ne);
for (i = 0; i < Ne; i++)
{
scanf("%d %d %d", &v1, &v2, &w);
/* InserEdge */
G[v1][v2] = w;
G[v2][v1] = w;
}
}

如上,是较为简单直观的无向图的表示方法。

用邻接表表示图

结构表示

【数据结构笔记23】C实现:表示图的多种方法(邻接矩阵、邻接表与相关拓展)_插入边_02

如上图,GNode结构体中包含图的属性;AdjList是包含各个链的数组;PtrToAdjNode指向的是AdjVNode,而AdjVNode(FirstEdge)是链中的第一链和之后的链,一个指向一个。

typedef struct GNode *PtrToGNode;
struct GNode
{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
AdjList G; /* 邻接表 */
};
typedef PtrToGNode LGraph;

typedef struct Vnode
{
PtrToAdjVNode FirstEdge;
DataType Data; /* 存顶点的可能有的数据 */
} AdjList[MaxVertexNum];
/* AdjList是邻接表类型 */

typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode
{
Vertex AdjV; /* 邻接点下标 */
WeightType Weight; /* 边权重 */
PtrToAdjVNode Next;
};

LGraph初始化

初始化一个有VertexNum个顶点但没有边的图。

typedef int Vertex; /* 用顶点下标表示顶点,为整形 */
LGraph CreateGraph(int VertexNum)
{
Vertex V, W;
LGraph Graph;

Graph = (LGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;

/* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */
for (V = 0; V < Graph->Nv; V++)
Graph->G[V].FirstEdge = NULL;

return Graph;
}

向LGraph中插入边

将结点插到对应结点的链表中。插到链表的哪里都可以,下面实现的算法是插入到头结点的,因为这样更好操作。

void InsertEdge(LGraph Graph, Edge E)
{
PtrToAdjVNode NewNode;

/* 插入边<V1, V2> */
/* 为V2建立新的邻接点 */
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V2;
NewNode->Weight = E->Weight;
/* 将V2插入V1的表头 */
NewNode->Next = Graph->G[E->V1].FirstEdge;
Graph->G[E->V1].FirstEdge = NewNode;

/* 若是无向图,还要插入边<V2, V1> */
/* 为V1建立新的邻接点 */
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V1;
NewNode->Weight = E->Weight;
/* 将V1插入V2的表头 */
NewNode->Next = Graph->G[E->V2].FirstEdge;
Graph->G[E->V2].FirstEdge = NewNode;
}

完整地建立一个LGraph

完整版,与MGraph同。