2021.11.14数据结构实验课作业——图的应用(最小生成树和最短路)

图的基本操作(必做题)
问题描述:在图的存储结构上实现以下算法:
① Prim和Kruskal算法;
② Dijkstra和Floyd算法;(Floyd算法选做)
③ 拓扑排序和关键路径算法。(关键路径算法选做)
输入输出:
输入图的顶点和边,输出最小生成树顶点和边、最短路径顶点序列、拓扑排序顶点序列、关键路径顶点序列。

点击查看代码Public.h
#pragma once

const int MaxVertex = 10; //图中最多顶点数
const int MaxEdge = 100; //图中最多边数
const int MaxValue = 10000; //图中最大边权

struct EdgeType { //定义边集数组的元素类型
	int from, to, weight; //假设权值为整数
	bool operator<(const EdgeType& x) const {
		return weight < x.weight;
	}
};

template<typename T>
struct VertexType { //定义点集的元素类型
	T data;
	int in_sum;
};
点击查看代码Prim.h
#pragma once
#include <iostream>
#include "Public.h"
using namespace std;

template<typename T>
class PGraph {
public:
	PGraph(T a[], int n, int m, EdgeType e[]); //构造函数,建立具有n个顶点m条边的图
	~PGraph() { } //析构函数
	void Prim(int v);
private:
	T vertex[MaxVertex]; //存放图中顶点的数组
	int edge[MaxVertex][MaxVertex]; //存放图中边的数组
	int vertexNum, edgeNum; //图的顶点数和边数
	int MinEdge(int edge[], int n);
};

template<typename T>
PGraph<T>::PGraph(T a[], int n, int m, EdgeType e[]) {
	vertexNum = n; edgeNum = m;
	for (int i = 0; i < vertexNum; ++i) //存储顶点
		vertex[i] = a[i];
	for (int i = 0; i < vertexNum; i++) //初始化邻接矩阵
		for (int j = 0; j < vertexNum; ++j)
			if (i == j)
				edge[i][j] = 0;
			else
				edge[i][j] = MaxValue;
	for (int i = 0; i < edgeNum; ++i)
		edge[e[i].from][e[i].to] = edge[e[i].to][e[i].from] = e[i].weight;
}

template<typename T>
void PGraph<T>::Prim(int v) {//从顶点v出发
	int i, j, k;
	int adjvex[MaxVertex], lowcost[MaxVertex];
	for (i = 0; i < vertexNum; i++) {//初始化辅助数组
		lowcost[i] = edge[v][i];
		adjvex[i] = v;
	}
	lowcost[v] = 0; //将顶点v加入集合U
	for (k = 1; k < vertexNum; k++) {//迭代n-1次
		j = MinEdge(lowcost, vertexNum); //寻找最短边的邻接点j
		cout << "(" << vertex[j] << ", " << vertex[adjvex[j]] << ")" << lowcost[j] << endl;
		lowcost[j] = 0; //顶点j加入集合U
		for (i = 0; i < vertexNum; i++) //调整辅助数组
			if (edge[i][j] < lowcost[i]) {
				lowcost[i] = edge[i][j];
				adjvex[i] = j;
			}
	}
}

template<typename T>
int PGraph<T>::MinEdge(int edge[], int n) {
	int index = 0, min = MaxValue;
	for (int i = 0; i < n; i++)
		if (edge[i] != 0 && edge[i] < min) {
			min = edge[i];
			index = i;
		}
	return index;
}
点击查看代码Kruskal.h
#pragma once
#include <iostream>
#include <algorithm>
#include "Public.h"
using namespace std;

template<typename T> //定义模板类
class KGraph {
public:
	KGraph(T a[], int n, int m, EdgeType e[]); //构造函数,生成n个顶点m条边的连通图
	~KGraph() { } //析构函数
	void Kruskal(); //Kruskal算法求最小生成树
private:
	int FindRoot(int parent[], int v); //求顶点v所在集合的根
	T vertex[MaxVertex]; //存储顶点的一维数组
	EdgeType edge[MaxEdge]; //存储边的边集数组
	int parent[MaxVertex]; //双亲表示法存储并查集
	int vertexNum, edgeNum;
};

template<typename T>
KGraph<T>::KGraph(T a[], int n, int m, EdgeType e[]) {
	vertexNum = n; edgeNum = m;
	for (int i = 0; i < vertexNum; ++i)
		vertex[i] = a[i];
	for (int i = 0; i < edgeNum; ++i)
		edge[i] = e[i];
}

template<typename T>
void KGraph<T>::Kruskal() {
	int num = 0, i, vex1, vex2;
	for (i = 0; i < vertexNum; ++i)
		parent[i] = -1; //初始化n个连通分量
	std::sort(edge, edge + edgeNum);
	for (num = 0, i = 0; num < vertexNum - 1; ++i) //依次考察最短边
	{
		vex1 = FindRoot(parent, edge[i].from);
		vex2 = FindRoot(parent, edge[i].to);
		if (vex1 != vex2) { //位于不同的集合
			cout << "(" << vertex[edge[i].from] << ", " << vertex[edge[i].to] << ")" << edge[i].weight << endl;
			parent[vex2] = vex1; //合并集合
			num++;
		}
	}
}

template<typename T>
int KGraph<T>::FindRoot(int parent[], int v) {//求顶点v所在集合的根
	int t = v;
	while (parent[t] > -1) //求顶点t的双亲一直到根
		t = parent[t];
	return t;
}
点击查看代码Dijkstra.h
#pragma once
#include <iostream>
#include <string>
#include "Public.h"
using namespace std;

template<typename T>
class DGraph {
public:
	DGraph(T a[], int n, int m, EdgeType e[]); //构造函数,建立具有n个顶点m条边的图
	~DGraph() { } //析构函数
	void Dijkstra(int v);
private:
	T vertex[MaxVertex]; //存放图中顶点的数组
	int edge[MaxVertex][MaxVertex]; //存放图中边的数组
	int vertexNum, edgeNum; //图的顶点数和边数
	int MinEdge(int edge[], int n); //求v点到其他所有顶点的最短路径
	bool visited[MaxVertex]; //标记该节点是否已经求得最短路径
};

template<typename T>
DGraph<T>::DGraph(T a[], int n, int m, EdgeType e[]) {
	vertexNum = n; edgeNum = m;
	for (int i = 0; i < vertexNum; ++i)
		visited[i] = false;
	for (int i = 0; i < vertexNum; ++i) //存储顶点
		vertex[i] = a[i];
	for (int i = 0; i < vertexNum; i++) //初始化邻接矩阵
		for (int j = 0; j < vertexNum; ++j)
			if (i == j)
				edge[i][j] = 0;
			else
				edge[i][j] = MaxValue;
	for (int i = 0; i < edgeNum; ++i)
		edge[e[i].from][e[i].to] = edge[e[i].to][e[i].from] = e[i].weight;
}

template<typename T>
void DGraph<T>::Dijkstra(int v) {//从v点出发
	int i, k, num, dist[MaxVertex];
	string path[MaxVertex];
	visited[v] = true;
	for (i = 0; i < vertexNum; ++i) { // 初始化数组dist和path
		dist[i] = edge[v][i];
		if (dist[i] != 100) {//假设100为边上权的最大值
			path[i].push_back(vertex[v]);
			path[i] = path[i] + ", ";
			path[i].push_back(vertex[i]);
		}
		else	path[i] = "";
	}
	for (num = 1; num < vertexNum; ++num) {
		k = MinEdge(dist, vertexNum); //在dist数组中找到最小值并返回下标
		cout << "到" << k << "点的最短路径为" << path[k] << "。 路径长度为" << dist[k] << endl;
		visited[k] = true;
		for (i = 0; i < vertexNum; ++i) //修改数组dist和path
			if (dist[i] > dist[k] + edge[k][i]) {
				dist[i] = dist[k] + edge[k][i];
				path[i] = path[k] + ", ";
				path[i].push_back(vertex[i]);
			}
	}
}

template<typename T>
int DGraph<T>::MinEdge(int edge[], int n) {
	int index = 0, min = 100;
	for (int i = 0; i < n; i++)
		if (!visited[i] && edge[i] != 0 && edge[i] < min) {
			min = edge[i];
			index = i;
		}
	return index;
}
点击查看代码TopSort.h
#pragma once
#include "Public.h"
#include <iostream>

template<typename T>
class TGraph {
public:
	TGraph(T a[], int n, int m, EdgeType e[]);
	~TGraph() {};
	void TopSort();
private:
	VertexType<T> vertex[MaxVertex];//存放图中顶点的数组
	int edge[MaxVertex][MaxVertex];//存放图中边的数组
	int vertexNum, edgeNum;//图的顶点数和边数
};

template<typename T>
TGraph<T>::TGraph(T a[], int n, int m, EdgeType e[]) {
	vertexNum = n; edgeNum = m;
	for (int i = 0; i < vertexNum; ++i) //存储顶点
		vertex[i].data = a[i], vertex[i].in_sum = 0;
	for (int i = 0; i < vertexNum; i++) //初始化邻接矩阵
		for (int j = 0; j < vertexNum; ++j)
			if (i == j)
				edge[i][j] = 0;
			else
				edge[i][j] = MaxValue;
	for (int i = 0; i < edgeNum; ++i) {
		edge[e[i].from][e[i].to] =  e[i].weight;
		++vertex[e[i].to].in_sum;
	}
	for (int i = 0; i < vertexNum; ++i)
		cout << vertex[i].data << ' ' << vertex[i].in_sum << endl;
}

template<typename T>
void TGraph<T>::TopSort() {
	int sta[MaxVertex], top = -1, x;
	for (int i = 0; i < vertexNum; ++i)
		if (vertex[i].in_sum == 0)
			sta[++top] = i;
	while (top != -1) {
		x = sta[top--];
		cout << vertex[x].data << ' ';
		for(int i=0; i<vertexNum; ++i)
			if (edge[x][i] != MaxValue) {
				--vertex[i].in_sum;
				if (vertex[i].in_sum == 0)
					sta[++top] = i;
			}
	}
}
/*
5
A B C D E
5
0 1 10
1 2 20
1 3 30
2 4 40
3 4 50
*/
点击查看代码main.cpp
#include <iostream>
#include "Dijkstra.h"
#include "Kruskal.h"
#include "TopSort.h"
#include "Prim.h"

int main(void) {
	char ch[100];
	int n, m;
	EdgeType e[100];
	cout << "请输入顶点数: ";
	cin >> n;
	cout << "请输入顶点: " << endl;
	for (int i = 0; i < n; ++i)
		cin >> ch[i];

	cout << "请输入边数: ";
	cin >> m;
	for (int i, j, w, k = 0; k < m; ++k) {
		cout << "请输入边依附的两个顶点的编号,以及边上的权值:";
		cin >> i >> j >> w;
		e[k].from = i;
		e[k].to = j;
		e[k].weight = w;
	}
	cout << "Kruskal 算法结果为: " << endl;
	KGraph<char> KG(ch, n, m, e);
	KG.Kruskal();

	cout << "Prim 算法结果为: " << endl;
	PGraph<char> PG(ch, n, m, e);
	PG.Prim(0);

	cout << "请输入需要求最短路的源点编号";
	int v;
	cin >> v;
	DGraph<char> DG(ch, n, m, e);
	cout << v << "起点到其他点的最短路为:" << endl;
	DG.Dijkstra(v);

	TGraph<char> TG(ch, n, m, e);
	cout << "拓扑排序结果为:";
	TG.TopSort();
	cin >> n;
	return 0;
}
/*
6
A B C D E F
9
0 1 34
0 5 19
0 2 46
1 4 12
2 5 25
5 4 26
5 3 25
3 4 38
2 3 17
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章