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
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章