圖的基本操作(必做題)
問題描述:在圖的存儲結構上實現以下算法:
① 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
*/