实验七 图的广度、深度优先遍历,拓扑排序、关键路径、最短路径、最小生成树

 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;
}

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值