zoukankan      html  css  js  c++  java
  • 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
    */
    
  • 相关阅读:
    写给太阳村张老师及其员工的公开信
    不尽的想法,不够的时间
    XP+新装SQL Server 2005出现无法连接的问题+解决
    【Windows编程】【网络编程】【基于网络端口通信的客户端应用程序】解决方案【示意程序】
    [VS2005SP1]如何创建从母版页继承的Web窗体?(SP1所带来的小小变更)
    小程序大问题,MSDN中一个小小示例所带来的疑问,一个关于DataList的一个简单应用
    [Oracle]ASP.NET+Oracle连接类conn.cs
    SQLServer2005出了点怪事~(应该是编码问题~)
    [ASPNET2.0]Membership类+SQLServer2005,AspNet_regsql.exe的使用
    Originality Life~Some Desktop Design (From Google Ideas)+ Pictures & PNG Files & 3DMAX Files download!
  • 原文地址:https://www.cnblogs.com/kuaileyongheng/p/15580198.html
Copyright © 2011-2022 走看看