数据结构实验3:图的应用

目的要求
1.掌握图的存储策略及其存储实现。
2.掌握图的深度、广度优先遍历的算法策略及其程序实现。
3.掌握图的常见算法策略及其程序实现。

实验内容
1.键入或随机生成数据,建立一个有向图的邻接表。
2.输出该邻接表。
3.以有向图邻接表为基础上,计算各顶点的度并输出。
4.以有向图邻接表为基础,输出其拓扑排序序列。
5.采用邻接表存储,实现无向图的非递归 DFS 遍历。
6.采用邻接表存储,实现无向图的 BFS 优先遍历。
7.判断无向图任意两个顶点间是否有路径,若有则输出路径上的顶点序列。
8.在主函数中设计一个简单的菜单,调用上述算法。

实验说明
1.类型定义(邻接表存储)

const int MAX_ VERTEX_NUM=8; // 顶点的最大个数
typedef struct ArcNode;
{
int adjvex ;
struct ArcNode *nextarc ;
int weight; // 边的权
} ArcNode ; // 表结点
typedef char VertexType; // 顶点元素类型
typedef struct VNode
{
int degree, indegree; // 顶点的度,入度
VertexType data;
ArcNode *firstarc;
} VNode /*头结点*/, AdjList[MAX_VERTEX_NUM] ;
typedef struct
{
AdjList vertices;
int vexnum, arcnum; // 顶点的实际数,边的实际数
} ALGraph ;

2.上述类型定义可根据情况适当调整。

源代码

#include "stdafx.h"
#include 
#include 
#include 
#include 
using namespace std;

#define MAX_VERTEX_NUM 8		// 顶点的最大个数
bool visited[MAX_VERTEX_NUM];//访问标志数组,已访问的顶点标记为true

typedef char VertexType;

typedef struct arcNode			//图的边表结点
{
	int adjvex;					//存储该顶点在顶点表中的下标
	struct arcNode * nextarc;	//指向下一个结点的指针
	int weight;					// 边的权
}ArcNode;

typedef struct vNode			//图的顶点表结点
{
	int degree, indegree;		//顶点的度,入度
	VertexType data;
	ArcNode * firstarc;			//边表头指针
}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct
{
	AdjList vertices;			//图的顶点表
	int vexnum, arcnum;         //顶点的实际数,边的实际数
}*ALGraph;

//图的邻接表初始化算法
ALGraph InitGraph(int vernum, int edgenum)
{
	ALGraph graphList = (ALGraph)malloc(sizeof(ALGraph));
	graphList->vexnum = vernum;		//初始化定点数
	graphList->arcnum = edgenum;	//初始化边数
	for (int i = 0;i < vernum;i++)
	{
		graphList->vertices[i].firstarc = NULL; //初始化每条链表为空
		graphList->vertices[i].degree = 0;		//初始化顶点的度为0
		graphList->vertices[i].indegree = 0;
	}
	return graphList;
}

//判断顶点是否存在于顶点表中,存在返回下标位置,不存在返回-1
int LocateVex(ALGraph graphList, VertexType v)
{
	int i;
	for (i = 0; i < graphList->vexnum; i++)
	{
		if (v == graphList->vertices[i].data)
			break;
	}

	if (i >= graphList->vexnum)   //表示没有找到顶点v
	{
		printf("not exist this vertex!\n");
		return -1;
	}
	return i;
}

//图的邻接表构建算法
void CreateGraph(ALGraph graphList)
{
	int i, w;
	VertexType v1, v2;
	ArcNode * tempNode = NULL;
	ArcNode * tempNode2 = NULL;
	//输入顶点
	for (i = 0;i < graphList->vexnum;i++)
	{
		printf("顶点%d:", i);
		graphList->vertices[i].data = getchar();
		while (graphList->vertices[i].data == '\n')
		{
			graphList->vertices[i].data = getchar();
		}
	}
	getchar();
	//建立边表
	printf("输入边(vi,vj)上的顶点和权值(如:vi vj w)\n");
	for (i = 0;i < graphList->arcnum;i++)
	{
		printf("第%d条边:", i + 1);
		scanf("%c %c %d", &v1, &v2, &w);
		getchar();
		int m = LocateVex(graphList, v1);//判断输入的顶点是否在顶点表中
		int n = LocateVex(graphList, v2);
		if (m == -1 || n == -1)
			return;
		tempNode = (ArcNode*)malloc(sizeof(struct arcNode));//申请空间,生成边表结点
		if (tempNode == NULL) {
			printf("Out of space!\n");
			return;
		}
		tempNode->adjvex = n;
		tempNode->weight = w;
		tempNode->nextarc = graphList->vertices[m].firstarc; //单链表的头插法
		graphList->vertices[m].firstarc = tempNode;

	}
}

//输出邻接表
void PrintGrapth(ALGraph graphList)
{
	int i;
	for (i = 0; i < graphList->vexnum; i++)
	{
		printf("顶点%c ", graphList->vertices[i].data);
		ArcNode *arc = graphList->vertices[i].firstarc;
		while (arc != NULL)
		{
			printf("—> <%c, %c> %d  ", graphList->vertices[i].data, graphList->vertices[arc->adjvex].data,arc->weight);
			arc = arc->nextarc;
		}
		putchar('\n');
	}
}

//计算各顶点的度及入度
void degree(ALGraph graphList)
{
	ArcNode * arc;
	for (int i = 0;i < graphList->vexnum;i++)
	{
		graphList->vertices[i].degree = 0;
		graphList->vertices[i].indegree = 0;
	}
	for (int i = 0;i < graphList->vexnum;i++)
	{
		for (arc = graphList->vertices[i].firstarc;arc;arc = arc->nextarc)
		{
			graphList->vertices[i].degree++; //出度
			graphList->vertices[arc->adjvex].degree++;
			graphList->vertices[arc->adjvex].indegree++;
		}
	}
}

//输出各顶点的度
void print_degree(ALGraph graphList)
{
	printf("Index	data	degree	indegree");
	for (int i = 0;i < graphList->vexnum;i++)
		printf("\n%3d%7c%9d%9d", i, graphList->vertices[i].data, graphList->vertices[i].degree, graphList->vertices[i].indegree);
	printf("\n");
}

//拓扑排序算法
int topologicalsort(ALGraph graphList)
{
	int count = 0; //计算输出顶点个数
	int nodenum;
	stack<int> nodestack;
	ArcNode * temp;
	degree(graphList); //计算每个顶点的入度
	for (int i = 0;i < graphList->vexnum;i++)
	{
		if (graphList->vertices[i].indegree == 0)
			nodestack.push(i);
	}
	while (!nodestack.empty())
	{
		nodenum = nodestack.top(); //取栈顶元素
		nodestack.pop();
		printf("%c ", graphList->vertices[nodenum].data); //输出拓扑序列
		temp = graphList->vertices[nodenum].firstarc;
		while (temp)
		{

			if (--graphList->vertices[temp->adjvex].indegree == 0) //若入度减少到0,则入栈
				nodestack.push(temp->adjvex);
			temp = temp->nextarc;
		}
		count++;
	}
	printf("\n");
	if (count == graphList->vexnum)
		return true;
	if (count != graphList->vexnum) {
		printf("此图有环,无拓扑序列!\n");
		return false; //说明这个图有环
	}
}

//无向图的非递归 DFS 遍历
void DFS(ALGraph graphList)
{
	int i, j;
	stack<int>s;
	ArcNode * p;
	memset(visited, 0, sizeof(visited));
	for (i = 0;i < graphList->vexnum;i++)
	{
		if (!visited[i]) {
			visited[i] = true;
			printf("%c ", graphList->vertices[i].data);
			s.push(i);
			p = graphList->vertices[i].firstarc;
			while (s.empty())
			{
				while (p) {
					if (!visited[p->adjvex]) {
						visited[p->adjvex] = true;
						printf("%c ", graphList->vertices[p->adjvex].data);
						s.push(p->adjvex);
						p = graphList->vertices[p->adjvex].firstarc;
					}
					else
						p = p->nextarc;
				}
				p = graphList->vertices[s.top()].firstarc;
				s.pop();
			}
		}
	}
	printf("\n");
}

//邻接表的BSF算法
void BFS(ALGraph graphList, int i)
{
	int tempno;
	ArcNode * p = NULL;
	queue<VertexType> Queue;						//队列的数据类型为char
	visited[i] = true;								//设置标记,表明已被访问
	printf("%c ", graphList->vertices[i].data);		//输出访问的顶点的值
	Queue.push(i);									//将刚访问的顶点入队
	while (!Queue.empty())
	{
		tempno = Queue.front();
		Queue.pop();
		//依次访问于当前结点相邻的点
		p = graphList->vertices[tempno].firstarc;
		while (p != NULL)
		{
			//如果其他顶点于当前顶点存在边且未被访问过
			if (!visited[p->adjvex])
			{
				visited[p->adjvex] = 1;  //做标记
				Queue.push(p->adjvex);   //入队
				printf("%c ", graphList->vertices[p->adjvex].data);
			}
			p = p->nextarc;              //移动到下一个顶点
		}
	}
	printf("\n");
}
void BFSGraphList(ALGraph graphList)
{
	int i;
	memset(visited, 0, sizeof(visited)); //初始化为点都没有被访问过
	for (i = 0;i < graphList->vexnum;i++)
		if (!visited[i]) //对未访问过的顶点调用DFS
			BFS(graphList, i);
}

bool record[MAX_VERTEX_NUM] = { 0 };
void dfsPath(ALGraph graph, int s, int end, int path[], int cnt)
{
	int i, j = 1;
	visited[s] = record[s] = true;
	path[cnt++] = s;
	ArcNode* edge = graph->vertices[s].firstarc;
	if (s == end)
	{
		for (i = 0; i < cnt - 1; i++)
			printf("%c-->", graph->vertices[path[i]].data);
		printf("%c", graph->vertices[path[i]].data);
		printf("\n");
		return;
	}
	for (; edge; edge = edge->nextarc)
	{
		if (!visited[edge->adjvex])
		{
			dfsPath(graph, edge->adjvex, end, path, cnt);
		}
		//回溯
		visited[edge->adjvex] = false;
	}
	if (s != end && record[end] == 0)
	{
		printf("不存在此路径!\n");
		return;
	}
}

//输出顶点i到顶点j之间的所有简单路径(不包含回路)
void findAllPath(ALGraph graph, int start, int end)
{
	printf("%c顶点和%c顶点之间的路径:\n", graph->vertices[start].data, graph->vertices[end].data);
	if (start == end)
		printf("%c ",graph->vertices[start].data);
	else
	{
		memset(visited, 0, sizeof(visited)); //初始化为点都没有被访问过
		int path[MAX_VERTEX_NUM];
		dfsPath(graph, start, end, path, 0);
	}
}


int main()
{
	int Index;
	ALGraph g = NULL;
	printf("					图的应用\n");
	printf("	****************************************************************\n");
	printf("		1.键入或随机生成数据,建立一个有向图的邻接表\n");
	printf("		2.输出该邻接表\n");
	printf("		3.以有向图邻接表为基础,计算各顶点的度并输出\n");
	printf("		4.以有向图邻接表为基础,输出其拓扑排序序列\n");
	printf("		5.采用邻接表存储,实现无向图的非递归 DFS 遍历\n");
	printf("		6.采用邻接表存储,实现无向图的 BFS 优先遍历\n");
	printf("		7.判断无向图任意两个顶点间是否有路径,若有则输出路径上的顶点序列\n");
	printf("		0.退出\n");
	printf("	****************************************************************\n");
	while (true)
	{
		printf("\n请输入一个序号:");
		scanf("%d", &Index);
		switch (Index)
		{
		case 0:
			return 0;
		case 1:
		{
			int vex, arc;
			printf("输入顶点数和边数(如 x,y):\n");
			scanf("%d,%d", &vex, &arc);
			g = InitGraph(vex, arc);
			CreateGraph(g);
			printf("建立成功!\n");
		}break;
		case 2:
		{
			if (g) {
				printf("\n邻接表:\n");
				PrintGrapth(g);
			}
			else
				printf("The Graph is NULL!\n");
		}break;
		case 3:
		{
			if (g) {
				degree(g);
				print_degree(g);
			}
			else
				printf("The Graph is NULL!\n");
		}break;
		case 4:
		{
			if (g) {
				printf("\n拓扑序列:");
				topologicalsort(g);
			}
			else
				printf("The Graph is NULL!\n");
		}break;
		case 5:
		{
			if (g) {
				printf("\n深度优先遍历:");
				DFS(g);
			}
			else
				printf("The Graph is NULL!\n");
		}break;
		case 6:
		{
			if (g) {
				printf("\n广度优先遍历:");
				BFSGraphList(g);
			}
			else
				printf("The Graph is NULL!\n");
		}break;
		case 7:
		{
			if (g) {
				int num1, num2;
				printf("请输入任意两个顶点的编号(如1,2):\n");
				scanf("%d,%d", &num1, &num2);
				if (num1 >= 0 && num1 < 6 && num2 >= 0 && num2 < 6)
					findAllPath(g, num1, num2);
				else
					printf("输入有误!\n");
			}
			else
				printf("The Graph is NULL!\n");
		}break;
		default:
			printf("输入有误,请输入数字0-7!\n");
			break;
		}
	}
	printf("\n");
	system("pause");
    return 0;
}

运行结果
数据结构实验3:图的应用_第1张图片
数据结构实验3:图的应用_第2张图片
有向图结构示例
数据结构实验3:图的应用_第3张图片

你可能感兴趣的:(数据结构)