C++数据结构-实验3-图的操作与实现

实验三 图的操作与实现

一、实验目的

1、图的邻接表和邻接矩阵存储
2、图的各种遍历算法实现
3、最小生成树的算法实现
4、最短路径的算法实现

二、实验类型:验证性

三、实验学时:4学时

四、实验教学的重点和难点

重点:图的基本操作和遍历
难点:邻接表和邻接矩阵的操作

五、实验内容:

利用图的邻接表或邻接矩阵存储结构设计并实现各种操作算法(任选一种存储结构来实现算法)。
1、图的邻接表和邻接矩阵存储
建立下图的邻接表或邻接矩阵,并输出之。
在这里插入图片描述

2、图的各种遍历算法实现
以0结点为起点实现上述图的深度优先和广度优先遍历算法。
3、最小生成树的算法实现
利用普里姆(Prim)算法或克鲁斯卡尔(Kruskal)算法求上图的最小生成树,算法实现代码必须有注释。
4、最短路径的算法实现
利用狄克斯特拉(Dijkstra)算法求上图中0结点到其它结点的最短路径,算法实现代码必须有注释。

#include<iostream>
#include<iomanip>
#include<cstdio>
// #include<queue>
using namespace std;
int graph[1000][1000];
int vis[1000], pre[1000],dis[1000];
const int inf = 0x3f3f3f3f;
struct Edge {
	int u, v, w;
}edge[1000];
int n, m, cnt;
struct QueueNode {
public:
	int data;
	QueueNode() { this->next = NULL; }
	QueueNode* next;

};
struct Queue {
public:
	QueueNode* begin, * end;  //设置头指针begin,尾指针end,左开右闭,移动end指针存储数据
	Queue() {
		//定义构造函数,初始化指针begin,尾指针end
		begin = new QueueNode;
		end = begin;
		end->next = NULL;
	}
	//返回第一个节点的数据
	int Front() {
		return begin->next->data;
	}
	//返回最后一个节点的数据
	int Back() {
		return end->data;
	}
	//判断队列是否为空,由于初始化时,从首指针begin的下一个节点开始存储数据,只需判断头尾是否相等就可以判断是否为空
	bool IsEmpty() {
		return begin == end ? 1 : 0;
	}
	//往队列中添加新节点数据
	void Push(int data) {
		QueueNode* tempNode = new QueueNode();
		tempNode->data = data;
		end->next = tempNode;
		end = tempNode;
		end->next = NULL;
	}
	//弹出队列首个节点
	int Pop() {
		if (IsEmpty())return -1;
		QueueNode* tempNode = this->begin->next;
		//移动队列中第一个有效的节点位置
		this->begin->next = this->begin->next->next;
		//判断该节点是否是唯一个的节点,若是则弹出后队列为空,尾指针end=头指针begin
		if (tempNode == this->end) this->end = this->begin;
		return tempNode->data;
	}
};

void ShowGraph() {
	cout << "输出原图:" << endl;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (graph[i][j] != inf) {
				cout << i << "->" << j << "的权值为:" << graph[i][j] << endl;
			}
		}
	}
}
//图的深度优先
void dfs(int u,int fa) {
	vis[u] = 1;
	cout << u << " ";
	for (int i = 0; i < n; i++) {
		if (i != u && i != fa && !vis[i] && graph[u][i] != inf) {
			dfs(i, u);
		}
	}
}
void bfs(int x) {
	Queue que;
	que.Push(x);
	while (!que.IsEmpty())
	{
		int u = que.Front(); que.Pop();
		if (vis[u])continue;
		vis[u] = 1;
		cout << u << " ";
		for (int i = 0; i < n; i++) {
			if (i != u && !vis[i] && graph[u][i] != inf) {
				que.Push(i);
			}
		}
	}
}
//按照边权值从小到大排序
void sort(Edge edge[],int m) {
	for (int i = 0; i < m; i++) {
		int k = i;
		for (int j = i + 1; j < m; j++) {
			if (edge[k].w > edge[j].w) {
				k = j;
			}
		}
		if (k != i) {
			Edge temp = edge[i];
			edge[i] = edge[k];
			edge[k] = temp;
		}
	}
}
//并查集
int Find(int x) {
	return pre[x] == x ? x : pre[x] = Find(pre[x]);
}
//Kruskal算法求最小生成树
int Kruskal(int n, int m) {
	for (int i = 0; i < n; i++) {
		pre[i] = i;
		vis[i] = 0;
	}
	int tmpcnt = 0, cost = 0;
	sort(edge, m);
	for (int i = 0; i < m; i++) {
		int fu = Find(edge[i].u), fv = Find(edge[i].v);
		if (fu != fv) {
			pre[fv] = fu;
			cost += edge[i].w;
			tmpcnt++;
			if (tmpcnt == n - 1)break;
		}
	}
	return !cost ? -1 : cost;
}
void Dijkstra(int x) {
	for (int i = 0; i < n; i++) {
		dis[i] = 0x3f3f3f3f;
		vis[i] = 0;
	}
	int start = x;
	dis[start] = 0;
	for (int i = 0; i < n; i++) {
		if (graph[start][i] != inf) {
			if (dis[i] > graph[start][i]) {
				dis[i] = graph[start][i];
			}
		}
	}
	for (int i = 0; i < n-1; i++) {
		int min = 0x3f3f3f3f;
		for (int j = 0; j < n; j++) {
			if (!vis[j] && dis[j] < min) {
				min = dis[j];
				start = j;
			}
		}
		vis[start] = 1;
		for (int k = 0; k < n; k++) {
			if (dis[k] > dis[start] + graph[start][k]) {
				dis[k] = dis[start] + graph[start][k];
			}
		}
	}
}
int main() {
	memset(graph, inf, sizeof(graph));
	cout << "输入非负无向图的点数n(下标从0开始)和边数m:" << endl;
	// 7 9
	 cin >> n >> m;
	 cout << "输入m条边的各个两顶点和权值:" << endl;
	 /*
	 0 1 28
	 0 5 10 
	 1 2 16
	 1 6 14
	 2 3 12
	 3 4 22
	 3 6 18
	 4 5 25
	 4 6 24
	 */
	for (int i = 0; i < m; i++) {
		int u, v, w; cin >> u >> v >> w;
		graph[u][v] = w;
		graph[v][u] = w;
		edge[cnt].u = u;
		edge[cnt].v = v;
		edge[cnt++].w = w;
	}
	ShowGraph();
	memset(vis, 0, sizeof(vis));
	cout << "图的深度优先:";
	dfs(0,-1);
	cout << endl;
	memset(vis, 0, sizeof(vis));
	cout << "图的广度优先:";
	bfs(0);
	cout << endl;
	cout << "输出最小生成树权值:" << Kruskal(n, m) << endl;
	cout << "输出图中 0 结点到其它结点的最短路径:";
	Dijkstra(0);
	for (int i = 1; i < n; i++)cout << dis[i] << " ";
	return 0;
}

在这里插入图片描述

  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值