实验十 图
1、实验目的:
(1)理解图的概念
(2)掌握图的常见存储结构。
(3)理解图的常见操作。
2、实验环境与设备:
已安装Visual Studio 2010(或其以上版本)集成开发环境的计算机。
3、实验原理:
(1)图的邻接矩阵存储。
(2)带权无向图(无向网)的最小生成树实现。
4、实验内容:
(1)实现图的邻接矩阵存储
(2)输出显示图的顶点、边和邻接矩阵
(3)求解图的最小生成树。
#include <stdio.h>
#include <stdlib.h>
// 预定义常量
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// 预定义类型
typedef int Status;
// 本程序定义常量
#define INFINITY INT_MAX // 表示最大值无穷大
#define MAX_VERTEX_NUM 20 // 最大顶点个数
// 本程序定义类型
typedef enum{ DG, DN, UDG, UDN } GraphKind; // 图的种类标记{有向图,有向网,无向图,无向网}
typedef int VRType ; // 边的类型,对无权图,用1或0表示相邻否;对带权图,则为权值类型
typedef char VertexType ; // 顶点元素类型
typedef char InfoType ; // 边信息
typedef struct ArcCell // 表示一条边
{
VRType adj; // 边
InfoType *info; // 该边相关信息的指针
}ArcCell, AdjMatrix[ MAX_VERTEX_NUM ][ MAX_VERTEX_NUM ];
typedef struct
{
VertexType vexs[ MAX_VERTEX_NUM ];// 顶点向量,存储顶点信息
AdjMatrix arcs; // 邻接矩阵,存储边
int vexnum; // 图的当前顶点数
int arcnum; // 图的当前边数
GraphKind kind; // 图的种类标记
}MGraph; // 采用邻接矩阵存储的图
typedef struct // 记录从顶点集U到V-U的代价最小的边的辅助数组定义:
{
VertexType adjvex;
VRType lowcost;
}closedge[ MAX_VERTEX_NUM ];
// 算法7.1 采用数组(邻接矩阵)表示法,构造图G。
Status CreateGraph( MGraph *pG ) {
printf( "请输入图的种类(0:有向图;1:有向网;2:无向图;3:无向网):" );
scanf("%d", &pG->kind); // 自定义输入函数,读入一个随机值
switch (pG->kind) {
case DG:
return CreateDG(pG); // 构造有向图G
case DN:
return CreateDN(pG); // 构造有向网G
case UDG:
return CreateUDG(pG); // 构造无向图G
case UDN:
return CreateUDN(pG); // 构造无向网G,算法7.2
default :
return ERROR;
}
} // CreateGraph
// 确定顶点u在G中位置
int LocateVex( MGraph G, VertexType u )
// 算法 7.2,采用数组(邻接矩阵)表示法,构造无向网G。
Status CreateUDN(MGraph *pG)
// 显示网络(包括有向网和无向网)
void DisplayNet( MGraph G )
//在数组minEdge中求非零的最小边
int minimum( closedge minEdge, MGraph G )
// 算法7.9,用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边。
void MiniSpanTree_PRIM(MGraph G, VertexType u)
// 主函数
int main( void )
{
MGraph G ;
printf( "请输入一个无向网:\n" );
CreateGraph( &G );
if( G.kind == DG || G.kind == UDG )
DisplayGraph( G );
else
DisplayNet( G );
printf( "该无向网的最小生成树为:\n" );
MiniSpanTree_PRIM( G, '1' ); //从1号顶点(即v1)开始使用普里姆算法求最小生成树
printf( "\n" );
return 0;
}
5、实验考核:
1)完成纸质版实验报告
2)提交电子版作业
6、执行结果示例如下:
构造上述图,程序的参考输入数据如下:
3
6
10
1
2
3
4
5
6
1 2 6
1 3 1
2 3 5
1 4 5
3 4 5
3 6 4
4 6 2
2 5 3
3 5 6
5 6 6
记不清了,代码里好像有bug,只适合这个实验能跑通
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 预定义常量
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// 预定义类型
typedef int Status;
// 本程序定义常量
#define INFINITY INT_MAX // 表示最大值无穷大
#define MAX_VERTEX_NUM 20 // 最大顶点个数
// 本程序定义类型
typedef enum{ DG, DN, UDG, UDN } GraphKind; // 图的种类标记{DG有向图, DN有向网, UDG无向图, UDN无向网}
typedef int VRType; // 边的类型,对无权图,用1或0表示相邻否;对带权图,则为权值类型
typedef char VertexType; // 顶点元素类型
typedef char InfoType; // 边信息
typedef struct ArcCell // 表示一条边
{
VRType adj; // 边
InfoType *info; // 该边相关信息的指针
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct
{
VertexType vexs[MAX_VERTEX_NUM];// 顶点向量,存储顶点信息
AdjMatrix arcs; // 邻接矩阵,存储边
int vexnum; // 图的当前顶点数
int arcnum; // 图的当前边数
GraphKind kind; // 图的种类标记
}MGraph; // 采用邻接矩阵存储的图
// 确定顶点u在G中位置
int LocateVex(MGraph G, VertexType u){
int i;
for (i = 0; i < G.vexnum; i++)
{
if (G.vexs[i] == u)
return i;
}
return -1;
}
typedef struct // 记录从顶点集U到V-U的代价最小的边的辅助数组定义:
{
VertexType adjvex;
VRType lowcost;
}closedge[MAX_VERTEX_NUM];
//创建有向图
Status CreateDG(MGraph *pG){
pG->kind = DG;
printf("有向图的点数:"); scanf_s("%d", &pG->vexnum);
printf("有向图的边数:"); scanf_s("%d", &pG->arcnum);
for (int i = 0; i < pG->vexnum; i++){ printf("G.vexs[%d]:", i); scanf_s("%d", &pG->vexs[i]); }
//初始化图的距离
for (int i = 0; i < pG->vexnum; i++)
for (int j = 0; j < pG->vexnum; j++)
pG->arcs[i][j].adj = INFINITY;
for (int i = 0; i < pG->arcnum; i++)
{
printf("\nv1 <char>, v2 <char>:");
int q, w;
scanf_s("%d %d", &q, &w);
q = LocateVex(*pG, q);
w = LocateVex(*pG, w);
pG->arcs[q][w].adj = 1;
}
return OK;
}
//创建有向网
Status CreateDN(MGraph *pG){
pG->kind = DG;
printf("有向网的点数:"); scanf_s("%d", &pG->vexnum);
printf("有向网的边数:"); scanf_s("%d", &pG->arcnum);
for (int i = 0; i < pG->vexnum; i++){ printf("G.vexs[%d]:", i); scanf_s("%d", &pG->vexs[i]); }
//初始化图的距离
for (int i = 0; i < pG->vexnum; i++)
for (int j = 0; j < pG->vexnum; j++)
pG->arcs[i][j].adj = INFINITY;
for (int i = 0; i < pG->arcnum; i++)
{
printf("\nv1 <char>, v2 <char>, v <int>:");
int q, w, e;
scanf_s("%d %d %d", &q, &w, &e);
q = LocateVex(*pG, q);
w = LocateVex(*pG, w);
pG->arcs[q][w].adj = e;
}
return OK;
}
//创建无向图
Status CreateUDG(MGraph *pG){
printf("无向图的点数:"); scanf_s("%d", &pG->vexnum);
printf("无向图的边数:"); scanf_s("%d", &pG->arcnum);
for (int i = 0; i < pG->vexnum; i++){ printf("G.vexs[%d]:", i); scanf_s("%d", &pG->vexs[i]); }
//初始化网的距离
for (int i = 0; i < pG->vexnum; i++)
for (int j = 0; j < pG->vexnum; j++)
pG->arcs[i][j].adj = 0;
for (int i = 0; i < pG->arcnum; i++)
{
printf("v1 <char>, v2 <char>:");
int q, w;
scanf_s("%d %d", &q, &w);
q = LocateVex(*pG, q);
w = LocateVex(*pG, w);
pG->arcs[q][w].adj = 1;
}
return OK;
}
//创建无向网
// 算法 7.2,采用数组(邻接矩阵)表示法,构造无向网G。
Status CreateUDN(MGraph *pG){
printf("无向网的点数:"); scanf_s("%d", &pG->vexnum);
printf("无向网的边数:"); scanf_s("%d", &pG->arcnum);
for (int i = 0; i < pG->vexnum; i++){ printf("G.vexs[%d]:", i); scanf_s("%d", &pG->vexs[i]); }
//初始化网的距离
for (int i = 0; i < pG->vexnum; i++)
for (int j = 0; j < pG->vexnum; j++)
pG->arcs[i][j].adj = INFINITY;
for (int i = 0; i < pG->arcnum; i++)
{
printf("v1 <char>, v2 <char>, v <int>:");
int q, w, e;
scanf_s("%d %d %d", &q, &w, &e);
q = LocateVex(*pG, q);
w = LocateVex(*pG, w);
pG->arcs[q][w].adj = e;
pG->arcs[w][q].adj = e;
}
return OK;
}
// 算法7.1 采用数组(邻接矩阵)表示法,构造图G。
Status CreateGraph(MGraph *pG) {
printf("请输入图的种类(0:有向图;1:有向网;2:无向图;3:无向网):");
scanf_s("%d", &pG->kind); // 自定义输入函数,读入一个随机值
switch (pG->kind) {
case DG:
return CreateDG(pG); // 构造有向图G
case DN:
return CreateDN(pG); // 构造有向网G
case UDG:
return CreateUDG(pG); // 构造无向图G
case UDN:
return CreateUDN(pG); // 构造无向网G,算法7.2
default:
return ERROR;
}
} // CreateGraph
// 显示网络(包括有向网和无向网)
void DisplayNet(MGraph G){
int i, j;
for (i = 0; i < G.vexnum; i++)
{
printf("\t%d", G.vexs[i]);
}
for (i = 0; i < G.vexnum; i++)
{
printf("\n%d", G.vexs[i]);
for (j = 0; j < G.vexnum; j++)
{
if (G.arcs[i][j].adj < INFINITY)
{
printf("\t%d", G.arcs[i][j].adj);
}
else
printf("\t∞");
}
}
printf("\n");
}
//在数组minEdge中求非零的最小边
int minimum(closedge minEdge, MGraph G){
int i = 0, j, k, min;
while (!minEdge[i].lowcost)
i++;
min = minEdge[i].lowcost; // 第一个不为0的值
k = i;
for (j = i + 1; j<G.vexnum; j++)
if (minEdge[j].lowcost>0)
if (min > minEdge[j].lowcost)
{
min = minEdge[j].lowcost;
k = j;
}
return k;
}
//// 算法7.9,用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边。
//void MiniSpanTree_PRIM(MGraph G, VertexType u){
// int i, j, k;
// closedge minedge;
// k = LocateVex(G, u);
// for (j = 0; j<G.vexnum; ++j) // 辅助数组初始化
// {
// if (j != k)
// {
// strcpy_s(&minedge[j].adjvex, 20, &u);
// minedge[j].lowcost = G.arcs[k][j].adj;
// }
// }
// minedge[k].lowcost = 0; // 初始,U={u}
// printf("最小代价生成树的各条边为:\n");
// for (i = 1; i<G.vexnum; ++i)
// { // 选择其余G.vexnum-1个顶点
// k = minimum(minedge, G); // 求出T的下一个结点:第K顶点
// printf("(%s-%d)\n", minedge[k].adjvex, G.vexs[k]); // 输出生成树的边
// minedge[k].lowcost = 0; // 第K顶点并入U集
// for (j = 0; j<G.vexnum; ++j)
// if (G.arcs[k][j].adj<minedge[j].lowcost)
// {
// // 新顶点并入U集后重新选择最小边
// strcpy_s(&minedge[j].adjvex, 20, &G.vexs[k]);
// minedge[j].lowcost = G.arcs[k][j].adj;
// }
// }
//
//}
void MiniSpanTree_PRIM(MGraph G, int u)
{
closedge minedge;
int i, j, k,quan=0;
for (j = 0; j < G.vexnum; ++j) //辅助数组初始化
if (j != u)
{
minedge[j].adjvex = G.vexs[u];
minedge[j].lowcost = G.arcs[u][j].adj;
}
minedge[u].lowcost = 0; //初始化U={u}
for (i = 0; i < G.vexnum; ++i)
{
int min = INT_MAX;
k = -1;
for (j = 0; j<G.vexnum; ++j) //求出最小生成树的下一个顶点k
if (minedge[j].lowcost >0 && minedge[j].lowcost < min)
{
k = j;
min = minedge[j].lowcost;
}//if
if (k < 0){
printf("\n该最小生成树的代价:%d\n", quan);
return;
}
printf("<%d,%d>", minedge[k].adjvex, G.vexs[k]); //输出生成树的边
quan += minedge[k].lowcost;
minedge[k].lowcost = 0; //第k顶点并入U集
for (j = 0; j < G.vexnum; ++j)
if (G.arcs[k][j].adj < minedge[j].lowcost) //新顶点并入U后,重新选择最小边
{
minedge[j].adjvex = G.vexs[k];
minedge[j].lowcost = G.arcs[k][j].adj;
}
}
}//MiniSpanTree_PRIM
// 主函数
int main(void)
{
MGraph G;
printf("请输入一个无向网:\n");
CreateGraph(&G);
if (G.kind == DG || G.kind == UDG)
//DisplayGraph(G);
return 0;
else
DisplayNet(G);
printf("该无向网的最小生成树为:\n");
MiniSpanTree_PRIM(G, 0); //从1号顶点(即v1)开始使用普里姆算法求最小生成树
printf("\n");
system("pause");
return 0;
}