第一关:创建采用邻接表存储的无向图
邻接表
对于图中每个顶点 vi,把所有邻接于 vi的顶点(对有向图是将从vi出发的弧的弧头顶点链接在一起)链接成一个带头结点的单链表,将所有头结点顺序存储在一个一维数组中。
例:下面左图G2对应的邻接表如右边所示。
/* 创建采用邻接表存储的无向图 实现文件 /
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ALGraph.h"
int visited[MAXVEX]; /*设访问标志数组为全局变量*/
void CreateUDG_ALG(ALGraph *g) /*构造无向图的邻接表*/
{
// 请在这里补充代码,完成本关任务
/********** Begin *********/
if(g==NULL) return;
int i , j , k , vnum , edgenum;
ENode *p;
scanf("%d%d%d",&g->kind,&vnum,&edgenum);
g->vexnum = vnum; //结点个数
g->edgenum = edgenum; //边的条数
for(i=0; i <vnum ;i++)
{
g->vertices[i].vex = i ;
g->vertices[i].firstarc = NULL;
} //初始化顶点表
for(i=0;i<edgenum;i++) //无向图具有双向连接的特点
{
scanf("%d%d",&j,&k);
p = ( ENode*)malloc(sizeof( ENode));
p->adjvex = k ;
p->nextarc = g->vertices[j].firstarc; //头插法插入
g->vertices[j].firstarc = p ;
p = ( ENode*)malloc(sizeof( ENode)); //头插法插入
p->adjvex = j ;
p->nextarc = g->vertices[k].firstarc;
g->vertices[k].firstarc = p ;
}
/********** End **********/ }
void PrintAdjList(ALGraph g) /*输出邻接表*/
{ int i,w;ENode *p;
for(i=0;i<g.vexnum;i++)
{
printf("%d",g.vertices[i].vex);
p=g.vertices[i].firstarc;
while(p)
{
w=p->adjvex;
printf("->%d",w);
p=p->nextarc;
}
printf("\n");
}
}
测试输入:
2 5 6 //图的类型为2表示UDG,图的顶点数为5,图的边数为6
0 1 0 3 1 2 1 4 2 3 2 4 //输入各条边的两顶点的编号,按顶点编号从小到大的顺序输入
预期输出:
0->3->1
1->4->2->0
2->4->3->1
3->2->0
4->2->1
第2关:图的深度优先遍历
设初始时,图中所有顶点未曾被访问过:
● 从图中某个顶点 v 出发,访问此顶点;
● 依次从 v 的未被访问的邻接点出发深度优先遍历图,直至图中所有和顶点 v 有路径相通的顶点都被访问到;
● 如果此时图中还有尚未访问的顶点,则另选一个尚未访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。
/* 图的深度优先遍历 实现文件 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ALGraph.h"
int visited[MAXVEX]; /*设访问标志数组为全局变量*/
void DFSTraverse(ALGraph g)/*深度优先遍历以邻接表存储的图g*/
{
int i;
for(i=0;i<g.vexnum;i++) /*访问标志数组初始化*/
visited[i]=0;
for(i=0;i<g.vexnum;i++)
if(!visited[i]) DFS(g,i); /*对尚未访问的顶点调用DFS函数*/
}
void DFS(ALGraph g, int i)/*从未被访问的顶点Vi出发深度优先遍历图g*/
{
// 请在这里补充代码,完成本关任务
/********** Begin *********/
ENode *p ; //表结点类型的指针
if(visited[i]==1) return ; //如果第i各节点已经被访问过,则返回
printf("%d ",i) ;
visited[i] = 1;
p = g.vertices[i].firstarc ;
while(p && visited[p->adjvex]==1)
p = p->nextarc;
if(p)
{
i = p->adjvex ;
DFS(g ,i);
}
/********** End **********/
}
void CreateUDG_ALG(ALGraph *g) /*构造无向图的邻接表*/
{
int i,j,k;
ENode *p;
//printf("请输入图的类型(0-3表示DG,DN,UDG,UDN)、顶点数、边数:\n");
scanf("%d%d%d",&g->kind,&g->vexnum,&g->edgenum);
for(i=0;i<g->vexnum;i++) /*构造头结点数组*/
{
g->vertices[i].vex=i;
g->vertices[i].firstarc=NULL; /*初始化头结点指针域为空*/ }
//printf("请按顶点编号从小到大的顺序输入各条边的两顶点:\n");
for(k=0;k<g->edgenum;k++) /*构造邻接表*/
{
scanf("%d%d",&i,&j); /*输入一条边所依附的两个顶点的编号*/
/*将顶点Vj插入到第i个单链表的表头,也就是用“头插法”建立一个单链表*/ p=(ENode *)malloc(sizeof(ENode)); /*生成表结点*/
p->adjvex=j; p->weight=0;
p->nextarc=g->vertices[i].firstarc; /*插入表结点*/
g->vertices[i].firstarc=p;
/*将顶点Vi插入到第j个单链表的表头,也就是用“头插法”建立一个单链表*/
p=(ENode *)malloc(sizeof(ENode));
p->adjvex=i; p->weight=0;
p->nextarc=g->vertices[j].firstarc;
g->vertices[j].firstarc=p;
}
}
测试输入:
2 5 6
0 1 0 3 1 2 1 4 2 3 2 4
预期输出:
0 3 2 4 1 //深度优先遍历的结果
**
第3关:图的广度优先遍历
**
设初始时,图中所有顶点未曾被访问过:
● 从图中某个顶点 v 出发,访问此顶点;
● 依次访问 v 的各个未被访问的多个邻接点;
● 分别从这些邻接点出发依次访问它们的邻接点,并使 “先被访问顶点的邻接点” 先于 “后被访问顶点的邻接点” 被访问,直至图中所有已被访问的顶点的邻接点都被访问
/* 图的广度优先遍历 实现文件 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ALGraph.h"
int visited[MAXVEX]; /*设访问标志数组为全局变量*/
void BFSTraverse(ALGraph g)
{
/*广度优先遍历以邻接表存储的图g,由于BFS要求”先被访问的顶点的邻接点也先被访问”,故需借助队列Q实现*/
// 请在这里补充代码,完成本关任务
/********** Begin *********/
int i;
SeqQueue *Q = (SeqQueue *)malloc(sizeof(SeqQueue)); //创建队列
for (i=0; i<g.vexnum; ++i){ /*访问标志数组初始化*/
visited[i] = 0;
}
InitQueue(Q); //队列的初始化
for (i=0; i<g.vexnum; ++i){
if(!visited[i]){ //如果第i个结点没有被访问
visited[i] = 1;
printf("%d ", g.vertices[i].vex);
EnQueue(Q, i); //将元素x入队
while (Q->len!=0){ //当队列不为空时,或者 Q->front != Q->rear
DeQueue(Q, &i); //将队头元素出队
ENode *p = g.vertices[i].firstarc;
while (p){
if (!visited[p->adjvex]){
visited[p->adjvex] = 1;
printf("%d ", g.vertices[p->adjvex].vex);
EnQueue(Q, p->adjvex); //将元素x入队
}
p = p->nextarc;
}
}
}
}
/********** End **********/ }
void InitQueue(SeqQueue *q)//队列的初始化{
q->front=q->rear=0;
q->len=0;}int QueueEmpty(SeqQueue q)//判队空
{
if(q.len==0)return 1;
else return 0;
}
void EnQueue(SeqQueue *q, datatype x)//将元素x入队
{
if(q->len==MAXSIZE)//判队满
{
printf("Queue is full\n");return;
}
q->data[q->rear]=x;
q->rear=(q->rear+1)%MAXSIZE;
q->len++;
}
void DeQueue(SeqQueue *q, datatype *x)//将队头元素出队
{
if(q->len==0)//判队空
{
printf("Queue is empty\n");return;
}
*x=q->data[q->front];
q->front=(q->front+1)%MAXSIZE;
q->len--;
}
void CreateUDG_ALG(ALGraph *g) /*构造无向图的邻接表*/
{
int i,j,k;ENode *p;
//printf("请输入图的类型(0-3表示DG,DN,UDG,UDN)、顶点数、边数:\n"); scanf("%d%d%d",&g->kind,&g->vexnum,&g->edgenum);
for(i=0;i<g->vexnum;i++) /*构造头结点数组*/
{
g->vertices[i].vex=i;
g->vertices[i].firstarc=NULL; /*初始化头结点指针域为空*/
} //printf("请按顶点编号从小到大的顺序输入各条边的两顶点:\n"); for(k=0;k<g->edgenum;k++) /*构造邻接表*/
{
scanf("%d%d",&i,&j); /*输入一条边所依附的两个顶点的编号*/
/*将顶点Vj插入到第i个单链表的表头,也就是用“头插法”建立一个单链表*/ p=(ENode *)malloc(sizeof(ENode)); /*生成表结点*/
p->adjvex=j; p->weight=0;
p->nextarc=g->vertices[i].firstarc; /*插入表结点*/
g->vertices[i].firstarc=p;
/*将顶点Vi插入到第j个单链表的表头,也就是用“头插法”建立一个单链表*/ p=(ENode *)malloc(sizeof(ENode));
p->adjvex=i; p->weight=0;
p->nextarc=g->vertices[j].firstarc;
g->vertices[j].firstarc=p;
}
}