目录
一、实验目的
- 熟练掌握图的非线性结构的特点。
- 掌握图的邻接矩阵和邻接表的存储结构。
- 掌握图的两种常用存储结构下的深度优先搜索和广度优先搜索操作和其它操作的实现
- 掌握用prim算法求图的最小生成树的原理
- 领会克鲁斯卡尔算法求连通图的最小生成树的过程和相关算法设计
- 掌握图的最小生成树的特点
二、实验要求
- 建立图(一)G的邻接矩阵,并输出
- 建立图(一)G的邻接表,并输出。
- 输出从顶点0开始的深度优先遍历序列
- 输出从顶点0开始的广度优先遍历序列
- 输出顶点0到顶点5的一条路径或所有路径
- 用prim算法和克鲁斯卡尔算法求下图的最小生成树,并打印输出。(选做)
- 销毁图G的邻接表
三、核心代码
//将邻接矩阵转化为邻接表
void MatToList(MGraph G,AdjGraph *&g)
{
int i,j;
EdgeNode *p;
g=(AdjGraph *)malloc(sizeof(AdjGraph));
for(i=0;i<G.n;i++)
g->vexlist[i].firstedge=NULL;
for(i=0;i<G.n;i++)
for(j=G.n-1;j>=0;j--)
if(G.edges[i][j]!=INF)
{
p=(EdgeNode *)malloc(sizeof(EdgeNode));
p->adjvex=j;
p->next=g->vexlist[i].firstedge; //头插法插入结点p
g->vexlist[i].firstedge=p;
}
g->vexnum=G.n; G.e=g->arcnum;
printf("图G的邻接表:\n");
for(i=0;i<g->vexnum;i++)
{
p=g->vexlist[i].firstedge;
printf("%c->",G.vexs[i]);
while(p!=NULL)
{
printf("%d->",p->adjvex);
p=p->next;
}
printf("NULL\n");
}
}
深度优先序列:
void DFS(AdjGraph *g,int v)
{
EdgeNode *p;
visited[v]=1;
printf("%d ",v);
p=g->vexlist[v].firstedge;
while(p!=NULL)
{
if(visited[p->adjvex]==0)
DFS(g,p->adjvex);
p=p->next;
}
}
void InitQueue(SqQueue *&r)
{
r=(SqQueue *)malloc(sizeof(SqQueue));
r->front=r->rear=-1;
}
bool QueueEmpty(SqQueue *r)
{
return (r->front==r->rear);
}
bool enQueue(SqQueue *&r,int e)
{
if(r->rear==MAX-1)
return false;
r->rear++;
r->data[r->rear]=e;
return true;
}
bool deQueue(SqQueue *&r,int &e)
{
if(r->front==r->rear)
return false;
r->front++;
e=r->data[r->front];
return true;
}
广度优先遍历
void BFS(AdjGraph *g,int v)
{
int w,i;
EdgeNode *p;
SqQueue *qu;
InitQueue(qu);
int visited[MAX];
for(i=0;i<g->vexnum;i++) visited[i]=0;
printf("%d",v);
visited[v]=1;
enQueue(qu,v);
while(!QueueEmpty(qu))
{
deQueue(qu,w);
p=g->vexlist[w].firstedge;
while(p!=NULL)
{
if(visited[p->adjvex]==0)
{
printf("%2d",p->adjvex);
visited[p->adjvex]=1;
enQueue(qu,p->adjvex);
}
p=p->next;
}
}
printf("\n");
}
找到一条路径
void FindaPath(AdjGraph *g,int u,int v,int path[],int d)
{
int w,i;
EdgeNode *p;
d++;path[d]=u;
visited2[u]=1;
if(u==v)
{
for(i=0;i<=d;i++)
printf("%d ",path[i]);
printf("\n");
return;
}
p=g->vexlist[u].firstedge;
while(p!=NULL)
{
w=p->adjvex;
if(visited2[w]==0)
FindaPath(g,w,v,path,d);
p=p->next;
}
}
找到所有路径
void FindAllPath(AdjGraph *g,int u,int v,int path[],int d)
{
int w,i;
EdgeNode *p;
d++;path[d]=u;
visited1[u]=1;
if(u==v)
{
for(i=0;i<=d;i++)
printf("%2d",path[i]);
printf("\n");
visited1[u]=0;
return;
}
p=g->vexlist[u].firstedge;
while(p!=NULL)
{
w=p->adjvex;
if(visited1[w]==0)
FindAllPath(g,w,v,path,d);
p=p->next;
}
visited1[u]=0;
}
prim算法求最小生成树
void Prim(MGraph G,int v)
{
int lowcost[MAXV];
int mindist;
int closest[MAXV],i,j,k;
for(i=0;i<G.n;i++)
{
lowcost[i]=G.edges[v][i];
closest[i]=v;
}
for(i=1;i<G.n;i++)
{
mindist=INF;
for(j=0;j<G.n;j++)
if(lowcost[j]!=0&&lowcost[j]<mindist)
{
mindist=lowcost[j];
k=j;
}
printf("边(%d,%d)权为:%d\n",closest[k],k,mindist);
lowcost[k]=0;
for(j=0;j<G.n;j++)
if(lowcost[j]!=0&&G.edges[k][j]<lowcost[j])
{
lowcost[j]=G.edges[k][j];
closest[j]=k;
}
}
}
四、实验记录
1. 建立图(一)G的邻接矩阵
依次输入有权图的顶点与权数建立邻接矩阵并输出。
2. 建立图(一)G的邻接表,将邻接矩阵转换为邻接表并输出。
3. 输出从顶点0开始的深度优先遍历序列
4. 输出从顶点0开始的广度优先遍历序列
5. 输出顶点0到顶点5的一条路径或所有路径
6. 用prim算法和克鲁斯卡尔算法求图的最小生成树,并打印输出。
Prim算法:
克鲁斯卡尔算法:
7. 销毁图G的邻接表,以及所有的任务输出结果如下:
五、总结
通过本次数据结构实验,我对图的非线性结构、存储结构以及相关操作有了更深入的了解。以下是我在实验过程中的一些心得和总结:
1.图的非线性结构特点:图是由顶点和边组成的一种数据结构,顶点之间可以有任意数量的边相连。这种非线性结构使得图在表示现实世界中的复杂关系时具有很高的灵活性。
2.图的邻接矩阵和邻接表存储结构:邻接矩阵是一种二维数组,用于表示图中顶点之间的连接关系;邻接表是一种链表结构,用于表示图中顶点之间的连接关系。这两种存储结构各有优缺点。
3.深度优先搜索(DFS)和广度优先搜索(BFS):DFS是一种递归的搜索方法,沿着图的深度方向进行搜索;BFS是一种迭代的搜索方法,沿着图的宽度方向进行搜索。在实验中,我掌握了这两种搜索方法的实现过程,并通过编程实现了从顶点0开始的DFS和BFS遍历序列。
六、完整报告和成果文件提取链接
完整可运行代码以及相关实验报告以下链接可获取:
链接:https://pan.baidu.com/s/1DuGfYm6_KDm04gUKWFSSVQ?pwd=lw6u
提取码:lw6u