1.实验目的
熟悉图的数组表示法和邻接表存储结构,掌握构造有向图和无向图的算法,在掌握以上知识的基础上,熟悉图的深度优先遍历算法,并实现。
2.实验内容
(1)图的数组表示法定义及基本操作的实现
(2)图的邻接表表示法定义和基本操作的实现
(3)写函数实现图的深度优先遍历(分别在两种结构上)
(4)在邻接表上实现拓扑排序、关键路径的求法,在邻接矩阵上实现最短路径,最小生成树的求法
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define ERROR 0
#define OK 1
#define OVERFLOW -2
#define INFINITY 1000 //最大值
#define MAX_VERTEX_NUM 20 //最大顶点数
#define STACK_INIT_SIZE 100
#define MAXQSIZE 100
typedef int QElemType;
typedef struct {
QElemType *base;
int front;
int rear;
}SqQueue;
typedef enum { DG, DN, UDG, UDN } GraphKind;//{有向图,有向网,无向图,无向网}
typedef int Status;
typedef int VRType;
typedef int InfoType;
typedef char VertexType;//数据类型
typedef struct ArcCell {
VRType adj;//VRType顶点关系类型,对于无权图用0,1表示相等否
//对带权图,则为权值类型
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;
Status QueueEmpty(SqQueue Q)
{
if (Q.front == Q.rear)
return OK;
else
return ERROR;
}
Status InitQueue(SqQueue *Q)
{
Q->base = (QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
if (!Q->base)
return OVERFLOW;
Q->front = Q->rear = 0;
return OK;
}
int QueueLength(SqQueue Q)
{
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}
Status EnQueue(SqQueue *Q, QElemType e)
{
if ((Q->rear + 1) % MAXQSIZE == Q->front)
return ERROR;
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXQSIZE;
return OK;
}
Status DeQueue(SqQueue *Q, QElemType *e)
{
if (Q->front == Q->rear) return ERROR;
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAXQSIZE;
return OK;
}
int LocateVex(MGraph *G, VertexType v)
{
int i;
for (i = 0; i < G->vexnum; i++)
{
if (G->vexs[i] == v)
return i;
}
return -1;
}
Status CreateUND(MGraph *G)
{
int i, j, k;
VertexType v1, v2;
VRType w;
printf("输入图的节点数和总边数:");
scanf_s("%d %d", &G->vexnum, &G->arcnum);
getchar();//接收输入节点数,边数后的
for (i = 0; i < G->vexnum; i++) {
printf("请输入第%d个顶点的信息:", i + 1);
scanf_s("%c", &G->vexs[i], 1);
getchar();//因为输入的是单个字符,要接收每次输入完之后的回车键
}
for (i = 0; i < G->vexnum; i++)
for (j = 0; j < G->vexnum; j++)
{
G->arcs[i][j].adj = INFINITY;
}
for (k = 0; k < G->arcnum; k++)
{
printf("输入图第%d条边的两个顶点和该边的权值:", k + 1);
scanf_s("%c %c %d", &v1, 1, &v2, 1, &w);
getchar();//接收每次输入完之后键入的回车键
i = LocateVex(G, v1);
j = LocateVex(G, v2);
G->arcs[i][j].adj = w;
G->arcs[j][i].adj = G->arcs[i][j].adj;
}
return OK;
}
Status PrintGraph(MGraph G) {
int i, j;
printf("\n图的顶点为:");
for (i = 0; i < G.vexnum; i++)
printf("%c", G.vexs[i]);
printf("\n图的邻接矩阵\n");
printf("\t");
for (i = 0; i < G.vexnum; i++)
printf("\t%8c", G.vexs[i]);
for (i = 0; i < G.vexnum; i++) {
printf("\n\n%8c", G.vexs[i]);
for (j = 0; j < G.vexnum; j++) {
if (G.arcs[i][j].adj == INFINITY)
printf("\t%8s", "00");
else
printf("\t%8d", G.arcs[i][j].adj);
}
printf("\n");
}
return OK;
}
typedef int Boolean;
Boolean visited[MAX_VERTEX_NUM];//访问标志数组
int FirstAdjVex(MGraph G, int v)
{//求v的第一个邻接点
for (int i = 0; i < G.vexnum; i++)
if (G.arcs[v][i].adj != 0)
return i;
return 0;
}
int NextAdjVex(MGraph G, int v, int w)
{//求v的相对于w的下一个邻接点
int k;
for (k = w + 1; k < G.vexnum; k++)
if (G.arcs[v][k].adj != 0)
return k;
return 0;
}
void DFS(MGraph G, int v)
{
int w;
visited[v] = TRUE;
printf("%2c", G.vexs[v]);
for (w = FirstAdjVex(G, v); w > 0; w = NextAdjVex(G, v, w))
{
if (!visited[w])
DFS(G, w);
}
}
void DFSTraverse(MGraph G)
{//对图做深度优先遍历
int v;
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE;//访问数组初始化,所有顶点都是未访问状态
for (v = 0; v < G.vexnum; v++)
{
if (!visited[v])
DFS(G, v);//对尚未访问的顶点调用DFS,若是连通图,只会执行一次
}
}
void BFSTraverse(MGraph G)
{
int v, w;
SqQueue Q;
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE;
InitQueue(&Q);//置空的辅助队列Q
for (v = 0; v < G.vexnum; v++)
{
if (!visited[v])
{//v尚未访问
visited[v] = TRUE;
printf("%2c", G.vexs[v]);
EnQueue(&Q, v);//v入队列
while (!QueueEmpty(Q))
{
DeQueue(&Q, &v);//队头元素出队并置为u
for (w = 0; w < G.vexnum; ++w)
{
if (!visited[w] && G.arcs[v][w].adj != INFINITY)
{
visited[w] = TRUE;
printf("%2c", G.vexs[w]);
EnQueue(&Q, w);
}
}
/*
for (w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w))
{
if (!visited[w] && G.arcs[v][w].adj != INFINITY)
{//w为u的尚未访问的邻接顶点
visited[w] = TRUE;
printf("%2c", G.vexs[w]);
EnQueue(&Q, w);
}
}
*/
}
}
}
}
int main()
{
MGraph G;
CreateUND(&G);
PrintGraph(G);
printf("图的深度优先遍历序列是:");
DFSTraverse(G);
printf("\n");
printf("图的广度优先遍历序列是:");
BFSTraverse(G);
printf("\n");
system("pause");
return 0;
}
被注释掉的部分有bug暂时没找出错误,广度优先遍历函数一直不能退出
#include<stdio.h>
#include<stdlib.h>
#define MAX_VERTEX_NUM 20
#define maxsize 100
#define OK 1
#define TRUE 1
#define FALSE 0
#define ERROR 0
#define OVERFLOW 0
#define STACK_INIT_SIZE 100
#define MAXQSIZE 100
typedef int QElemType;
typedef char VertexType;
typedef int Status;
typedef int InfoType;
typedef struct ArcNode { //表结点类型定义
int adjvex;//顶点位置编号
struct ArcNode *nextarc;//指向下一表结点的指针
InfoType *info;//该弧相关信息的指针
} ArcNode;
/* 顶点表*/
typedef struct VNode { //头结点及数组类型定义
VertexType data;//顶点信息
ArcNode *firstarc;//指向第一条弧
} VNode, AdjList[MAX_VERTEX_NUM];
/*图结构*/
typedef struct {
AdjList vertices;//头结点数组
int vexnum;//图当前顶点数
int arcnum;//图当前弧数
} ALGraph;
typedef struct
{
QElemType *base;
int front;
int rear;
}SqQueue;
Status QueueEmpty(SqQueue Q)//队列空返回1,不空返回0
{
if (Q.rear == Q.front)
return OK;
else return ERROR;
}
Status InitQueue(SqQueue *Q)
{
Q->base = (QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
if (!Q->base) return OVERFLOW;
Q->front = Q->rear = 0;
return OK;
}
int QueneLength(SqQueue Q)
{
return(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}
Status EnQueue(SqQueue *Q, QElemType e)
{
if ((Q->rear + 1) % MAXQSIZE == Q->front) return ERROR;
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXQSIZE;
return OK;
}
Status DeQueue(SqQueue *Q, QElemType *e)
{
if (Q->front == Q->rear) return ERROR;
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAXQSIZE;
return OK;
}
void CreateUDG(ALGraph *G)
{//头插法建立图的邻接表结构
printf("输入图的顶点数和边数:");
scanf_s("%d %d", &G->vexnum, &G->arcnum);
getchar(); //接受回车
printf("输入图中各个结点的值\n");
for (int i = 1; i <= G->vexnum; i++)
{//读入顶点信息,建顶点表
printf("请输入第%d个顶点的信息:", i);
scanf_s("%c", &G->vertices[i].data, 1);
getchar();//接收回车
G->vertices[i].firstarc = NULL;//将边表置为空表
}
for (int i = 1; i <= G->arcnum; i++)
{//建立边<s,d><d,s>的信息
int s, d;
ArcNode*p, *q;
printf("输入第%d条边有关联的顶点的序号:", i);
scanf_s("%d %d", &s, &d);
getchar();//接受回车
p = (ArcNode*)malloc(sizeof(ArcNode));//边的指针
q = (ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = d; q->adjvex = s;
p->nextarc = G->vertices[s].firstarc; G->vertices[s].firstarc = p;//<d,s>,逆向建立链表
q->nextarc = G->vertices[d].firstarc; G->vertices[d].firstarc = q;//<s,d>
}
}
void PrintGraph(ALGraph G)
{
int i;
for (i = 1; i <= G.vexnum; i++)
{
printf("%d->", i);
while (1)
{
if (G.vertices[i].firstarc == NULL)
{
printf("^");
break;
}
printf("%d->", G.vertices[i].firstarc->adjvex);
G.vertices[i].firstarc = G.vertices[i].firstarc->nextarc;
}
printf("\n");
}
}
typedef int Boolean;
Boolean visited[maxsize];
Status(*VisitFunc)(int v, ALGraph G);
Status Print(int i, ALGraph G)
{
printf("%2c", G.vertices[i].data);
return OK;
}
void DFS(ALGraph G, int v)
{
ArcNode *w;
visited[v] = TRUE;
VisitFunc(v, G);
for (w = G.vertices[v].firstarc; w; w = w->nextarc)
if (!visited[w->adjvex]) DFS(G, w->adjvex); //对v的尚未访问的邻接顶点w调用DFS
}
void DFSTraverse(ALGraph G)
{
int v;
VisitFunc = Print; //使用全局变量VisitFunc,使DFS不必设函数指针参数
for (v = 1; v <= G.vexnum; ++v) visited[v] = FALSE;
for (v = 1; v <= G.vexnum; ++v)
if (!visited[v]) DFS(G, v);//对每个未被访问的顶点调用DFS
printf("\n");
}
void BFSTraverse(ALGraph G, Status(*Visit)(int v, ALGraph))
{
int u, v;
ArcNode *w;
Visit = Print;
for (v = 1; v <= G.vexnum; ++v)
visited[v] = FALSE;
SqQueue Q;
InitQueue(&Q);//初始化
for (v = 1; v <= G.vexnum; ++v)
if (!visited[v])//v没有被访问
{
visited[v] = TRUE;
Visit(v, G);
EnQueue(&Q, v);//入队列
while (!QueueEmpty(Q))
{
DeQueue(&Q, &u);
w = G.vertices[u].firstarc;
for (w = G.vertices[u].firstarc; w; w = w->nextarc)
if (!visited[w->adjvex])//w为u的尚未访问的邻接顶点
{
visited[w->adjvex] = TRUE;
Visit(w->adjvex, G);
EnQueue(&Q, w->adjvex);
}
}
}
printf("\n");
}
int main()
{
ALGraph G;
CreateUDG(&G);
PrintGraph(G);
printf("深度优先遍历的序列是:");
DFSTraverse(G);
printf("广度优先遍历的序列是:");
BFSTraverse(G, Print);
system("pause");
return 0;
}