问题及代码:
/*
copyright (t) 2016,烟台大学计算机学院
*All rights reserved.
*文件名称:1.cpp
*作者:常锐
*完成日期:2016年11月17日
*版本号:v1.0
*问题描述:假设图G采用邻接表存储,分别设计实现以下要求的算法:
(1)输出出图G中每个顶点的出度;
(2)求出图G中出度最大的一个顶点,输出该顶点编号;
(3)计算图G中出度为0的顶点数;
(4)判断图G中是否存在边<i,j>。
利用下图作为测试用图(见知识点总结部分),输出结果。
提示:(1)分别设计函数实现算法;(2)不要全部实现完再测试,而是实现一个,测试一个;(3)请利用图算法库。
*输入描述:无
*程序输出:测试结果
*/
graph.h:
#include <stdio.h>
#define MAXV 100 //定义最大顶点数100
#define limitless 9999 //处理“无穷大”
typedef int InfoType; //定义顶点与边的相关信息
typedef int Vertex;
typedef struct //定义顶点类型
{
int no; //顶点编号
InfoType info; //顶点其他信息
} VertexType;
typedef struct //定义图邻接矩阵类型
{
int edges[MAXV][MAXV]; //邻接矩阵边数组
int n; //顶点数
int e; //边数
VertexType vexs[MAXV]; //存放顶点信息
} MGraph;
typedef struct ANode //定义边节点类型
{
int adjvex; //该边终点编号
struct ANode *nextarc; //指向下一条边的指针
InfoType info; //该边相关信息
} ArcNode;
typedef struct VNode //定义邻接表头节点类型
{
Vertex data; //顶点信息
ArcNode *firstarc; //指向第一条边的指针
} VNode;
typedef VNode AdjList[MAXV]; //AdjList: 邻接表类型
typedef struct //定义图邻接表类型
{
AdjList adjlist; //邻接表
int n; //图中顶点数
int e; //图中边数
} ALGraph;
void ArrayToMat(int *Arr, int n, MGraph &g); //用普通数组构造图的邻接矩阵
void ArrayToList(int *Arr, int n, ALGraph *&G); //用普通数组构造图的邻接表
void MatToList(MGraph g,ALGraph *&G); //将邻接矩阵g转换成邻接表G
void ListToMat(ALGraph *G,MGraph &g); //将邻接表G转换成邻接矩阵g
void DispMat(MGraph g); //输出邻接矩阵g
void DispAdj(ALGraph *G); //输出邻接表G
graph.cpp:
#include <malloc.h>
#include "graph.h"
//几点说明:
//功能:由一个反映图中顶点邻接关系的二维数组,构造出用邻接矩阵存储的图
//参数:Arr - 数组名,由于形式参数为二维数组时必须给出每行的元素个数,在此将参数Arr声明为一维数组名(指向int的指针)
// n - 矩阵的阶数
// g - 要构造出来的邻接矩阵数据结构
void ArrayToMat(int *Arr, int n, MGraph &g) //用普通数组构造图的邻接矩阵
{
int i,j;
int edgenum=0; //边数初始化为0
g.n=n;
for(i=0;i<g.n;i++)
{
for(j=0;j<g.n;j++)
{
g.edges[i][j]=Arr[i*n+j]; //计算存储位置
if(g.edges[i][j]!=0 && g.edges[i][j]!=limitless)
edgenum++;
}
}
g.e=edgenum;
}
void ArrayToList(int *Arr, int n, ALGraph *&G) //用普通数组构造图的邻接表
{
int i,j;
int edgenum=0; //边数初始化为0
ArcNode *p; //后续操作中创建的新节点
G=(ALGraph *)malloc(sizeof(ALGraph));
G->n=n;
for(i=0;i<n;i++) //邻接表所有头节点指针域置初值
G->adjlist[i].firstarc=NULL;
for(i=0;i<n;i++) //遍历邻接矩阵中的每个元素
{
for(j=n-1;j>=0;j--)
{
if(Arr[i*n+j]!=0)
{
p=(ArcNode *)malloc(sizeof(ArcNode)); //创建节点*p
p->adjvex=j;
p->info=Arr[i*n+j];
p->nextarc=G->adjlist[i].firstarc; //头插法插入*p
G->adjlist[i].firstarc=p; //指向第一条边的指针指向*p
}
}
}
G->e=edgenum;
}
void MatToList(MGraph g,ALGraph *&G) //将邻接矩阵g转换成邻接表G
{
int i,j;
ArcNode *p;
G=(ALGraph *)malloc(sizeof(ALGraph));
for(i=0;i<g.n;i++) //给邻接表所有头节点的指针域置初值
G->adjlist[i].firstarc=NULL;
for(i=0;i<g.n;i++) //遍历邻接矩阵中的每个元素
{
for(j=g.n-1;j>=0;j--)
{
if(g.edges[i][j]!=0)
{
p=(ArcNode *)malloc(sizeof(ArcNode)); //创建一个节点*p
p->adjvex=j; //终点编号赋值
p->nextarc=G->adjlist[i].firstarc; //头插法插入节点*p
G->adjlist[i].firstarc=p; //连接
}
}
}
G->n=g.n;
G->e=g.e;
}
void ListToMat(ALGraph *G,MGraph &g) //将邻接表G转换成邻接矩阵g
{
//前提要求:g的实参调用前已经初始化为全0
int i;
ArcNode *p;
for(i=0;i<G->n;i++)
{
p=G->adjlist[i].firstarc; //*p指向每个顶点的第一条边
while(p!=NULL) //依次遍历
{
g.edges[i][p->adjvex]=1; //p不为空指针时对应矩阵元素赋值1
p=p->nextarc; //*p指向下一条边
}
}
g.n=G->n;
g.e=G->e;
}
void DispMat(MGraph g) //输出邻接矩阵g
{
int i,j;
for(i=0;i<g.n;i++)
{
for(j=0;j<g.n;j++)
if(g.edges[i][j]==limitless)
printf("%3s","∞");
else
printf("%3d",g.edges[i][j]);
printf("\n");
}
}
void DispAdj(ALGraph *G) //输出邻接表G
{
int i;
ArcNode *p;
for (i=0; i<G->n; i++)
{
p=G->adjlist[i].firstarc;
printf("%3d: ",i);
while (p!=NULL)
{
printf("-->%d/%d ",p->adjvex,p->info);
p=p->nextarc;
}
printf("\n");
}
}
main.cpp:(注:这里直接使用了参考解答中的测试函数)
#include <stdio.h>
#include "graph.h"
int OutDegree(ALGraph *G,int v) //返回图G中编号为v的顶点的出度
{
ArcNode *p;
int num=0; //num记录每个顶点的出度
p=G->adjlist[v].firstarc;
while (p!=NULL)
{
num++;
p=p->nextarc;
}
return num;
}
void OutDs(ALGraph *G) //输出图G中每个顶点的出度
{
int i;
for(i=0;i<G->n;i++)
printf("顶点 %d 的出度是 %d\n",i,OutDegree(G,i));
}
void OutMaxDs(ALGraph *G) //输出图G中出度最大的一个顶点
{
int i;
int maxnode; //记录出度最大的顶点
int maxdegree=0; //出度最大值赋0
for(i=0;i<G->n;i++)
{
if(OutDegree(G,i)>maxdegree)
{
maxnode=i;
maxdegree=OutDegree(G,i);
}
}
printf("出度最大的顶点为:%d,其出度为%d\n",maxnode,maxdegree);
}
void ZeroDs(ALGraph *G) //计算图G中出度为0的顶点数
{
int i,zeronode=0;
for(i=0;i<G->n;i++)
{
if(OutDegree(G,i)==0)
zeronode++;
}
printf("图G中出度为0的顶点数为:%d\n",zeronode);
}
bool Arc(ALGraph *G,int i,int j) //返回图G中是否存在边<i,j>
{
bool existence=false; //existence记录边是否存在,开始假定不存在
ArcNode *p;
p=G->adjlist[i].firstarc;
while(p!=NULL)
{
if(p->adjvex==j) //存在边,existence置为true,跳出循环
{
existence=true;
break;
}
p=p->nextarc;
}
return existence;
}
int main() //测试主函数
{
ALGraph *G;
int A[7][7]=
{
{0,1,1,1,0,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,1,1,0},
{0,0,0,0,0,0,1},
{0,0,0,0,0,0,0},
{0,0,0,1,1,0,1},
{0,1,0,0,0,0,0}
};
ArrayToList(A[0], 7, G);
printf("(1)各顶点出度:\n");
OutDs(G);
printf("(2)最大出度的顶点信息:");
OutMaxDs(G);
printf("(3)出度为0的顶点:");
ZeroDs(G);
printf("(4)边<2,6>存在吗?");
if(Arc(G,2,6))
printf("是\n");
else
printf("否\n");
printf("\n");
return 0;
}
运行结果:
知识点总结:
邻接表存储的图的相关操作
附:测试用图:
心得体会:
通过操作邻接表存储的图,结合已经建好的算法库,加深了对图的存储结构的认识和理解。不难看出,邻接矩阵与邻接表、图结构三者是密不可分的。