图的基本操作
还是以书上的例子来演示图的基本操作,跟着敲一遍,试着理解每一行代码,多少会有收获滴,多敲敲就可以熟练运用啦
例:
以如下图所示的带权有向图为例,编写测试上述图操作函数的程序
代码实现:
注:
代码包含一个存放顶点的单链表头文件《ListVertex.h》和图的操作头文件《AdjMGraph.h》,一个测试源文件《main.cpp》
ListVertex.h:
#pragma once
#include<stdio.h>
#include<stdlib.h>
/*存放图的顶点的单向链表*/
typedef char DataType;
typedef struct nodeVertex
{
DataType data; //数据域
nodeVertex *next; //指针域
}NodeVertex;
/*初始化链表*/
void initiateSeqList(NodeVertex **head)
{
(*head) = (NodeVertex*)malloc(sizeof(NodeVertex));
(*head)->next = NULL;
}
/*求链表长度*/
int listVertexLength(NodeVertex *head)
{
NodeVertex *p = head;
int i = 0;
while (p->next != NULL)
{
i++;
p = p->next;//编写的时候容易把这个语句忘掉,造成死循环,出不来结果
}
return i;
}
/*指定位置插入结点*/
void listVertexInsert(NodeVertex *head, int index, DataType vertex)
{
NodeVertex *p = head;
NodeVertex *q = (NodeVertex*)malloc(sizeof(NodeVertex));
q->data = vertex; //数据赋给新的结点
q->next = NULL; //新结点的指针域默认先置为空
if (index < 0 || index > listVertexLength(p)) //防止报错
{
printf("参数不合法!插入失败!\n");
return;
}
for (int i = 0; i < index; i++) //遍历链表,直到指定位置index
p = p->next;
q->next = p->next; //将p的下一个结点接在新结点后面
p->next = q; //将新结点接在p后面
}
/*指定位置删除结点*/
void listVertexDelete(NodeVertex *head, int index, DataType* vertex)
{
NodeVertex *p = head;
if (index < 0 || index>=listVertexLength(p)) //防止报错
{
printf("参数不合法!插入失败!\n");
return;
}
if (p->next == NULL) //考虑空链表的情况
{
printf("链表已空!\n");
return;
}
for (int i = 0; i < index; i++) //遍历链表,直到指定位置
p = p->next;
if (p->next->next != NULL) //如果要删除的不是最后一个结点,需要判断p->next->next是否为空,否则程序出错
p->next = p->next->next;
else
p->next = NULL; //如果要删除的是最后一个结点,直接把p的指针域置空
}
/*遍历输出结点*/
void listVertexPrint(NodeVertex *head)
{
NodeVertex* p = head;
while (p->next != NULL)
{
printf("%c ", p->next->data);
p = p->next;
}
printf("\n");
}
AdjMGraph.h:
#pragma once
#include"ListVertex.h"
#define MaxVertices 100 //最大顶点数
#define MaxWeight 10000 //最大权值
/*图的结构体*/
typedef struct adjMGraph
{
NodeVertex *VerTices; //存放顶点
int edge[MaxVertices][MaxVertices];//存边的二维数组
int numOfEdges; //边的条数
}AdjMGraph;
//初始化图
void adjMGraphInitiate(AdjMGraph *map, int n)
{
int i, j;
for (int i = 0; i < n; i++) //初始化边
for (int j = 0; j < n; j++)
if (i == j)
map->edge[i][j] = 0; //自身到自身,没有边,默认权值为0
else
map->edge[i][j] = MaxWeight;
map->numOfEdges = 0; //初始化边数
initiateSeqList(&(map->VerTices)); //单链表初始化
}
/*插入顶点*/
void InsetVertex(AdjMGraph *map, DataType vertex)
{
listVertexInsert(map->VerTices, listVertexLength(map->VerTices), vertex); //利用链表 在指定位置增加结点函数 插入顶点
}
/*插入边*/
void InsertEdge(AdjMGraph *map, int val1, int val2, int weight) //i,j,权值
{
//存放边的是一个二维数组,当i,j小于0或者i,j大于等于顶点个数,会出错
if (val1 < 0 || val1 >= listVertexLength(map->VerTices) || val2 < 0 || val2 >= listVertexLength(map->VerTices))
{
printf("参数不合法!\n");
return;
}
map->edge[val1][val2] = weight; //赋边的权值
map->numOfEdges++; //图中边的条数+1
}
/*删除边*/
void DeleteEdge(AdjMGraph *map, int val1, int val2)
{
//同上,当i,j小于0或者i,j大于等于顶点个数,会出错
if (val1 < 0 || val1 >= listVertexLength(map->VerTices) || val2 < 0||val2>=listVertexLength(map->VerTices)||val1==val2)
{
printf("参数不合法!\n");
return;
}
//如果该边没有被赋过值(初始化的时候默认是MaxWeight),或者i==j时,没有这条边
if (map->edge[val1][val2] == MaxWeight || val1 == val2)
{
printf("该边不存在!\n");
return;
}
map->edge[val1][val2] = MaxWeight; //若有这条边,重新恢复默认值MaxWeight
map->numOfEdges--; //边数-1
}
/*取第一个邻接顶点*/
int GetFirstVex(AdjMGraph map, int index)
/*在图中寻找index顶点的第一个邻接顶点*/
{
int col;
/*参数不合法*/
if (index < 0 || index>listVertexLength(map.VerTices))
{
printf("参数不合法!\n");
return -1;
}
for (col = 0; col < listVertexLength(map.VerTices); col++) //在同行取得(邻接矩阵中),一定在结点集合内
if (map.edge[index][col] > 0 && map.edge[index][col] < MaxWeight)//值肯定在0到maxweight之间,
return col;
return -1;
}
/*在图中寻找val1顶点的邻接顶点val2的下一个邻接顶点*/
int GetNextVex(AdjMGraph map, int val1, int val2)
{
int col;
if (val1 < 0 || val1 >= listVertexLength(map.VerTices) || val2 < 0 || val2 >= listVertexLength(map.VerTices))
{
printf("参数不合法!\n");
return -1;
}
for (col = val2 + 1; col < listVertexLength(map.VerTices); col++) //col赋初值为cal2+1,在同行取得(邻接矩阵中)
{
if (map.edge[val1][col] > 0 && map.edge[val1][col] < MaxWeight)
return col;
return -1;
}
}
//边的结构体,有行、列、权值三个属性
struct RowColWeight
{
int row;
int col;
int weight;
};
//在图中插入n个顶点信息V,和e条边信息E
void CreatGraph(AdjMGraph *map, DataType V[], int n, RowColWeight E[], int e)
{
int i, k;
adjMGraphInitiate(map, n); //初始化图
for (int i = 0; i < n; i++) //增加n个顶点
InsetVertex(map, V[i]);
for (k = 0; k < e; k++) //增加n条边
InsertEdge(map, E[k].row,E[k].col, E[k].weight);
}
main.c:
#include"ListVertex.h"
#include"AdjMGraph.h"
int main()
{
AdjMGraph g1; //定义图
DataType a[] = { 'A','B','C','D','E' }; //图的顶点集合
RowColWeight row[] = { {0,1,10},{0,4,20},{1,3,30},{2,1,40},{3,2,50} }; //边的权值
int p[9][9],q[9][9];
int n = 5, e = 5; //五个顶点和五条边
int i, j, k;
CreatGraph(&g1,a,n,row,e); //创建有五个顶点,五条边的图
//DeleteEdge(&g1, 0, 4); //删除邻接矩阵i,j为0,4的边;
printf("顶点集合为:");
listVertexPrint(g1.VerTices); //打印顶点集合(链表)
printf("\n");
printf("权值集合为:\n");
for (i = 0; i < listVertexLength(g1.VerTices); i++)
{
for (j = 0; j < listVertexLength(g1.VerTices); j++)
printf("%5d ", g1.edge[i][j]);
printf("\n");
}
system("pause");
return 0;
}
运行结果:
代码编译器:Visual Studio 2017
ok