题解系列之图的存储(不定期更新)
邻接矩阵
1.题目描述
在邻接矩阵存储结构上实现图的基本操作 matrix_insert_vertex 和matrix_insert_arc,有关定义如下:
typedef int VertexType;
typedef enum{
DG, UDG
}GraphType;
typedef struct{
VertexType vertex[MAX_VERTEX_NUM]; //顶点向量
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
int vexnum, arcnum; //图的当前顶点数和弧数
GraphType type; //图的种类标志
}MatrixGraph;
int matrix_locate_vertex(MatrixGraph MG, VertexType vex); //返回顶点 v 在vertex数组中的下标,如果v不存在,返回-1
bool matrix_insert_vertex(MatrixGraph G, VertexType v);
bool matrix_insert_arc(MatrixGraph *G, VertexType v, VertexType w);
当成功插入顶点或边时,函数返回true,否则返回false。
2.题解
分析知如顶点或边已存在、插入边时顶点v或w不存在时两个函数返回false
,同时要特别注意边界条件和细节!比如防止数组溢出。
bool matrix_insert_vertex(MatrixGraph* G, VertexType v)
{
if (G->vexnum + 1 > MAX_VERTEX_NUM) {
return false;
}
if (matrix_locate_vertex(G, v) == -1) {
G->vertex[G->vexnum] = v;
for (int count = 0; count <= G->vexnum; count++) {
G->arcs[count][G->vexnum] = 0;
G->arcs[G->vexnum][count] = 0;
}
++G->vexnum;
return true;
}
return false;
}
bool matrix_insert_arc(MatrixGraph* G, VertexType v, VertexType w)
{
if (G->type == DG) {
if ((matrix_locate_vertex(G, v) != -1) && (matrix_locate_vertex(G, w) != -1)) {
int x = matrix_locate_vertex(G, v);
int y = matrix_locate_vertex(G, w);
G->arcs[x][y] = 1;
++G->arcnum;
return true;
} else {
return false;
}
}
if (G->type == UDG) {
if ((matrix_locate_vertex(G, v) != -1) && (matrix_locate_vertex(G, w) != -1)) {
int x = matrix_locate_vertex(G, v);
int y = matrix_locate_vertex(G, w);
G->arcs[x][y] = 1;
G->arcs[y][x] = 1;
++G->arcnum;
return true;
} else {
return false;
}
}
return false;
}
邻接表1
1.题目描述
试在邻接表存储结构上实现图的基本操作 insert_vertex(插入顶点) 和 insert_arc(插入边),相关定义如下:
typedef int VertexType;
typedef enum{
DG, UDG
}GraphType;
typedef struct ArcNode
{
int adjvex;
InfoPtr *info;
struct ArcNode *nextarc;
}ArcNode;
typedef struct VNode
{
VertexType data;
ArcNode *firstarc;
}VNode;
typedef struct
{
VNode vertex[MAX_VERTEX_NUM];
int vexnum, arcnum;
GraphType type;
}ListGraph;
int locate_vertex(ListGraph* G, VertexType v); //返回顶点 v 在vertex数组中的下标,如果v不存在,返回-1
bool insert_vertex(ListGraph *G, VertexType v);
bool insert_arc(ListGraph *G, VertexType v, VertexType w);
当成功插入顶点或边时,函数返回true,否则返回false。
2.题解
思路是分有向图的无向图两种情况讨论
bool insert_vertex(ListGraph* G, VertexType v)//插入顶点
{
if (G->vexnum + 1 > MAX_VERTEX_NUM) {
return false;
}
if (locate_vertex(G, v) == -1) {
G->vertex[G->vexnum].data = v;
G->vertex[G->vexnum].firstarc = NULL;
++G->vexnum;
return true;
}
return false;
}
bool insert_arc(ListGraph* G, VertexType v, VertexType w)//插入边
{
if (G->type == DG) {//无向图的情况
if ((locate_vertex(G, v) != -1) && (locate_vertex(G, w) != -1)) {
int a = locate_vertex(G, v);
int b = locate_vertex(G, w);
struct ArcNode* p = G->vertex[a].firstarc;
while (p != NULL) {
p = p->nextarc;
}
p->nextarc->adjvex = G->vertex[b].data;//把b的值插入到a的邻接表中
return true;
} else {
return false;
}
}
if (G->type == UDG) {//有向图的情况
if ((locate_vertex(G, v) != -1) && (locate_vertex(G, w) != -1)) {
int a = locate_vertex(G, v);
int b = locate_vertex(G, w);
struct ArcNode* p = G->vertex[a].firstarc;
struct ArcNode* q = G->vertex[b].firstarc;
while (q != NULL) {
q = q->nextarc;
}
while (p != NULL) {
p = p->nextarc;
}
p->nextarc->adjvex = G->vertex[b].data;
q->nextarc->adjvex = G->vertex[a].data;
return true;
} else {
return false;
}
}
}
邻接表2
1.题目描述
试在邻接表存储结构上实现图的基本操作 del_vertex(删除顶点),相关定义如下:
typedef int VertexType;
typedef enum{
DG, UDG
}GraphType;
typedef struct ArcNode{
int adjvex;
InfoPtr info;
struct ArcNode nextarc;
}ArcNode;
typedef struct VNode{
VertexType data;
ArcNode firstarc;
}VNode;
typedef struct{
VNode vertex[MAX_VERTEX_NUM];
int vexnum, arcnum;
GraphType type;
}ListGraph;
int locate_vertex(ListGraph *G, VertexType v); //返回顶点 v 在vertex数组中的下标,如果v不存在,返回-1
bool del_vertex(ListGraph *G, VertexType v); //删除顶点 v
当成功删除顶点或边时,函数返回true,否则返回false。
2.题解
思路是分出度和入度的两种情况进行删除,在出度的情况下,应该删除这个顶点的所有后继邻接表;在入度的情况下,删除其他顶点和这个顶点所有的边。
bool del_vertex(ListGraph* G, VertexType v)
{
ArcNode *p, *pre, *del;
if (locate_vertex(G, v) != -1) {
int i = locate_vertex(G, v);
G->vertex[i].data = 0; //删除顶点信息
p = G->vertex[i].firstarc;
G->vertex[i].firstarc = NULL;
while (p) { //删除出度的弧
del = p;
p = p->nextarc;
free(del);
--G->arcnum; //弧数量减一
}
for (int j = 0; j < G->vexnum; j++) { //删除入度的弧
p = G->vertex[j].firstarc;
while (p) {
if (p->adjvex == i) {
if (p == G->vertex[j].firstarc) { //被删除弧结点为第一个结点
del = p;
p = p->nextarc;
G->vertex[j].firstarc = p;
pre = NULL;
free(del);
G->arcnum--; //弧数量减一
break;
} else {
del = p;
p = p->nextarc;
pre->nextarc = p;
free(del);
G->arcnum--; //弧数量减一
break;
}
}
pre = p;
p = p->nextarc;
}
}
G->vexnum--; //顶点数减一
return true;
} else {
return false;
}
}