实验名称 图
- 实验目的:
1. 掌握图的基本存储方法;
2. 掌握有关图的操作算法并用高级语言实现;
3. 熟练掌握图的两种遍历方法。
4.掌握图的最短路径算法的实现。
二、实验环境:
Visual C++
三、实验内容:
(写出主要的内容)
假设以一个带权有向图表示某一区域的公交线路网,图中顶点代表一些区域中的重要场所,弧代表已有的公交线路,弧上的权表示该线路上的票价(或搭乘所需时间),试设计一个交通指南系统,指导前来咨询者以最低的票价或最少的时间从区域中的某一场所到达另一场所。
四、实验步骤
1. 定义结点结构,定义图结构。
2.存储图信息;
3. 定义求点到其它点的最短路径函数;
4. 写出主函数。
五、实现操作
#include <stdio.h>
#include <stdlib.h>
#define MAX_VERTEX_NUM 20 //图的最大顶点数
#define MAXQSIZE 30 //队列的最大容量
#define INFINITY 32768 /*表示极大值,即∞*/
#define TRUE 1
#define FALSE 0
#define ERROR -1
#define OK 1
typedef int QueueElementType;
typedef struct Node
{
QueueElementType data; /*数据域*/
struct Node *next; /*指针域*/
}LinkQueueNode;
typedef struct
{
LinkQueueNode *front;
LinkQueueNode *rear;
}LinkQueue;
/*初始化操作。*/
int InitQueue(LinkQueue *Q)
{
/* 将Q初始化为一个空的链队列 */
Q->front=(LinkQueueNode *)malloc(sizeof(LinkQueueNode));
if(Q->front!=NULL)
{
Q->rear=Q->front;
Q->front->next=NULL;
return(TRUE);
}
else return(FALSE); /* 溢出!*/
}
/*入队操作。*/
int EnterQueue(LinkQueue *Q,QueueElementType x)
{
/* 将数据元素x插入到队列Q中 */
LinkQueueNode *NewNode;
NewNode=(LinkQueueNode * )malloc(sizeof(LinkQueueNode));
if(NewNode!=NULL)
{
NewNode->data=x;
NewNode->next=NULL;
Q->rear->next=NewNode;
Q->rear=NewNode;
return(TRUE);
}
else return(FALSE); /* 溢出!*/
}
/*出队操作。*/
int DeleteQueue(LinkQueue *Q,QueueElementType *x)
{
/* 将队列Q的队头元素出队,并存放到x所指的存储空间中 */
LinkQueueNode * p;
if(Q->front==Q->rear)
return(FALSE);
p=Q->front->next;
Q->front->next=p->next; /* 队头元素p出队 */
if(Q->rear==p) /* 如果队中只有一个元素p,则p出队后成为空队 */
Q->rear=Q->front;
*x=p->data;
free(p); /* 释放存储空间 */
return(TRUE);
}
int IsEmpty(LinkQueue *Q)
{
if(Q->front==Q->rear)
return(TRUE);
else
return(FALSE);
}
#define ElemType char
#define MAXSIZE 100 /*此处的宏定义常量表示线性表可能达到的最大长度*/
typedef struct
{
ElemType elem[MAXSIZE]; /*线性表占用的数组空间*/
int last; /*记录线性表中最后一个元素在数组elem[ ]中的位置(下标值),空表置为-1*/
}SeqList;
void InitList(SeqList *L)
{
L->last=-1;
}
int AddTail(SeqList *L, ElemType e)
{
if(L->last>=MAXSIZE-1)
{
printf("表已满,无法添加!");
return ERROR;
}
L->elem[++L->last]=e;
return OK;
}
typedef enum{DG, DN, UDG, UDN} GraphKind; /*图的种类:DG表示有向图, DN表示有向网, UDG表示无向图, UDN表示无向网*/
typedef char VertexData; /*假设顶点数据为字符型*/
typedef struct ArcNode
{
int adj;/*对于无权图,用1或0表示是否相邻;对带权图,则为权值类型*/
} ArcNode;
typedef struct
{
VertexData verxs[MAX_VERTEX_NUM]; /*顶点向量*/
ArcNode arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /*邻接矩阵*/
int vexnum,arcnum; /*图的顶点数和弧数*/
GraphKind kind; /*图的种类标志*/
}AdjMatrix; /*(Adjacency Matrix Graph)*/
int LocateVertex(AdjMatrix *G,VertexData v) /*求顶点位置函数*/
{
int j=ERROR,k;
for(k=0;k<G->vexnum;k++)
if(G->verxs[k]==v)
{
j=k;
break;
}
return(j);
}
int CreateDN(AdjMatrix *G) /*创建一个有向网*/
{
int i,j,k,weight;
VertexData v1,v2;
printf("输入图的类型:0-有向图,1-有向网,2-无向图,3-无向网\n");
scanf("%d",&G->kind);
printf("输入图的顶点数和弧数:");
scanf("%d,%d",&G->arcnum,&G->vexnum);
for(i=0;i<G->vexnum;i++)
for(j=0;j<G->vexnum;j++)
G->arcs[i][j].adj=INFINITY;
printf("输入图的顶点:");
for(i=0;i<G->vexnum;i++)
scanf("%c",&G->verxs[i]);
printf("输入一条弧的两个顶点及权值:");
for(k=0;k<G->arcnum;k++)
{
scanf("%c,%c,%d",&v1,&v2,&weight);
i=LocateVertex(G,v1);
j=LocateVertex(G,v2);
G->arcs[i][j].adj=weight;
//请编程实现此函数功能;
}
return(OK);
}
int visit(int v0)
{
printf("%d",v0);
return(OK);
}
int visited[MAX_VERTEX_NUM]; /*访问标志数组*/
/*用邻接矩阵方式实现深度优先搜索*/
void DepthFirstSearch(AdjMatrix g,int v0) /* 图g 为邻接矩阵类型AdjMatrix */
{
int vj;
visit(v0);visited[v0]=TRUE;
for(vj=0;vj<g.vexnum;vj++)
if(!visited[vj]&&g.arcs[v0][vj].adj==1)
DepthFirstSearch(g,vj);
//请编程实现此函数功能
}/* DepthFirstSearch */
/*用邻接矩阵方式实现广度优先搜索*/
void BreadthFirstSearch(AdjMatrix g,int v0)
{
int vj;
visit(v0);visited[v0]=TRUE;
for(vj=0;vj<g.vexnum;vj++)
if(g.arcs[v0][vj].adj==1)
BreadthFirstSearch(g,vj);
//请编程实现此函数功能;
}
void TraverseGraph1(AdjMatrix g)
/*对图g进行深度优先搜索*/
{
int vi;
for(vi=0;vi<g.vexnum;vi++)
visited[vi]=FALSE ;/*访问标志数组初始*/
for(vi=0;vi<g.vexnum;vi++) /*调用深度遍历连通子图的操作*/
if (!visited[vi])
DepthFirstSearch(g,vi); /*若图g是连通图,则此循环调用函数只执行一次*/
}/* TraverseGraph */
void TraverseGraph2(AdjMatrix g)
/*对图g进行广度优先搜索*/
{
int vi;
for(vi=0;vi<g.vexnum;vi++)
visited[vi]=FALSE ;/*访问标志数组初始*/
for(vi=0;vi<g.vexnum;vi++) /*调用深度遍历连通子图的操作*/
if (!visited[vi])
DepthFirstSearch(g,vi); /*若图g是连通图,则此循环调用函数只执行一次*/
}/* TraverseGraph */
#define INFINITY 32768
typedef unsigned int WeightType;
typedef SeqList VertexSet;
int Member(VertexData v, VertexSet s)
{
int i;
for(i=0;i<=s.last;i++)
if(s.elem[i]==v)
return TRUE;
return FALSE;
}
void ShortestPath_DJS(AdjMatrix g,int v0,WeightType dist[MAX_VERTEX_NUM],VertexSet path[MAX_VERTEX_NUM])
/* path[i]中存放顶点i的当前最短路径。dist[i]中存放顶点i的当前最短路径长度*/
{
int i,t,k;
unsigned int min;
VertexSet s;
for(i=0;i<g.vexnum;i++)
{ InitList(&path[i]);
dist[i]=g.arcs[v0][i].adj;
if(dist[i]<INFINITY)
{ AddTail(&path[i],g.verxs[v0]);
AddTail(&path[i],g.verxs[i]);
}
}
InitList(&s);
AddTail(&s,g.verxs[v0]);
for(t=1;t<=g.vexnum;i++)
if(!Member(g.verxs[i],s)&&dist[i]<min)
{ k=i;min=dist[i];}
if(min==INFINITY) return;
AddTail(&s,g.verxs[k]);
for(i=0;i<g.vexnum;i++)
if(!Member(g.verxs[i],s)&&g.arcs[k][i].adj!=INFINITY&&(dist[k]+g.arcs[k][i].adj<dist[i]))
{
dist[i]=dist[k]+g.arcs[k][i].adj;
path[i]=path[k];
AddTail(&path[i],g.verxs[i]);
}
//请编程实现此函数功能;
}
void print(AdjMatrix G,VertexSet s[])
{
int i,j;
for(i=0;i<G.vexnum;i++)
{
if(s[i].last==-1)
printf("到%c点没有路径。\n",G.verxs[i]);
else
{
for(j=0;j<=s[i].last;j++)
printf("%c->",s[i].elem[j]);
printf("\b\b \n");
}
}
}
int main()
{
AdjMatrix G; //采用邻接表结构的图
char sp;
int choice,flag=1,v0;
WeightType dist[MAX_VERTEX_NUM];
VertexSet path[MAX_VERTEX_NUM];
printf("本程序实现图的操作:\n");
printf("可以进行创建图, 深度优先、广度优先操作,实现最短路径查找等的应用。\n");
while(flag)
{
printf("请选择: \n");
printf("1.创建图\n");
printf("2.深度优先遍历\n");
printf("3.广度优先遍历\n");
printf("4.最短路径查找\n");
printf("5.退出程序\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
CreateDN(&G);
break;
case 2:
if(G.kind==DN||G.kind==UDN)
printf("此为加权网!不适合遍历。\n");
else
{
TraverseGraph1(G);
printf("\b\b \n");
}
break;
case 3:
if(G.kind==DN||G.kind==UDN)
printf("此为加权网!不适合遍历。\n");
else
{
TraverseGraph2(G);
printf("\b\b \n");
}
break;
case 4:
printf("输入源点:\n");
fflush(stdin);
scanf("%c",&sp);
v0=LocateVertex(&G,sp);
ShortestPath_DJS(G,v0,dist,path);
print(G,path);
break;
default:
flag=0;
printf("程序结束,按任意键退出!\n");
}
}
}
六、心得体会:
1、图中顶点间的关系可以任意的,因此图是最复杂的的非线性结构,它的表达力强。
2、图的遍历算法是图应用的重要基础。
3、深度优先遍历算法是以递归技术为支撑的,而广度优先遍历算法是以队列技术为支撑。