实验目的:
掌握图的基本应用的实现。
实验内容与要求:
请完成下列图的应用:
⑴求无向连通网的最小生成树;
⑵对有向图进行拓扑排序;
⑶求AOE网的关键路径;
⑷求单源点出发的最短路径。
四个题目分别创建了四个类,而在visual studio c++2019中,每个类都有 .h和 .cpp两个文件,如下图所示:
先贴主函数(图的应用.cpp)
#include"undirected_network.h" //求无向连通网的最小生成树
#include"Topological_sorting.h" //对有向图进行拓扑排序
#include"AOE_net.h" //求AOE网的关键路径
#include"shortest_path.h" //求单源点出发的最短路径
#include<iostream>
using namespace std;
//菜单
void show() {
cout << "---图的应用---" << endl;
cout << "1.求无向连通网的最小生成树" << endl;
cout << "2.对有向图进行拓扑排序" << endl;
cout << "3.求AOE网的关键路径" << endl;
cout << "4.求单源点出发的最短路径" << endl;
cout << "0.退出" << endl;
cout << endl;
}
int main() {
int n;
show();
while (1) {
cin >> n;
if (n == 0)break;
else if (n == 1) {
undirected_network u;
u.create_net();
u.find_minTree();
u.print();
}
else if (n == 2) {
Topological_sorting t;
t.create();
t.topology_sort();
}
else if (n == 3) {
AOE_net a;
a.create();
a.aoe();
}
else if (n == 4) {
shortest_path s;
s.create();
s.Floyd();
s.print();
}
else {
cout << "error";
}
}
}
求无向连通网的最小生成树
undirected_network.h
#include<iostream>
#include<vector>
using namespace std;
const int MAXX = 9999;
class undirected_network {
private:
int vexnum = 0; //顶点数
int arcnum = 0; //边数
vector<char>vexs;
int** g; //邻接矩阵
int** closedge; //prim算法实现工具
public:
void create_net(); //创建无向网
void find_minTree(); //找最小生成树
void print(); //输出最小生成树
bool exist(char a, int& z) { //判断该点是否在网中,若在则为真
for (unsigned int i = 0; i < vexs.size(); i++) {
if (a == vexs[i])z = i;
}
if (z == -1)return false;
return true;
}
};
undirected_network.cpp
#include "undirected_network.h"
void undirected_network::create_net()
{
cout << "无向连通网的最小生成树" << endl;
char a, b; int w;
cout << "输入顶点数:";
cin >> vexnum;
g = new int* [vexnum];
closedge = new int* [vexnum];
for (int i = 0; i < vexnum; i++) {
cout << "输入第" << i + 1 << "个顶点名称(例:a):";
cin >> a;
vexs.push_back(a);
}
for (int i = 0; i < vexnum; i++) {
g[i] = new int[vexnum];
for (int j = 0; j < vexnum; j++) {
g[i][j] = MAXX;
}
}
cout << endl;
cout << "输入边数:";
cin >> arcnum;
int z1 = -1; int z2 = -1;
for (int i = 0; i < arcnum; i++) {
cout << "输入第" << i + 1 << "条边的信息(顶点1 顶点2 权重)(例:a b 1):";
cin >> a >> b >> w;
if (!exist(a, z1)) {
cout << endl << "顶点" << a << "不存在" << endl;
i--;
}
else if (!exist(b, z2)) {
cout << endl << "顶点" << b << "不存在" << endl;
i--;
}
else {
if (g[z1][z2] != MAXX || g[z2][z1] != MAXX) {
cout << endl << "该边已存在!";
i--;
}
else {
g[z1][z2] = w;
g[z2][z1] = w;
}
z1 = -1; z2 = -1;
}
}
}
void undirected_network::find_minTree()
{
//初始化二维数组
for (int i = 0; i < vexnum; i++) {
closedge[i] = new int[3];
closedge[i][0] = 0;
closedge[i][1] = g[0][i];
closedge[i][2] = MAXX;
}
//取第一个顶点
int k = 0;
closedge[k][0] = 0;
closedge[k][1] = 0;
closedge[k++][2] = 0;
int x = MAXX, y = -1;
while (k != vexnum) {
for (int i = 0; i < vexnum; i++) {
if (closedge[i][1] != 0 && closedge[i][1] < x) {
x = closedge[i][1];
y = i;
}
}
x = MAXX;
//选出下一个顶点
closedge[y][1] = 0;
closedge[k++][2] = y;
for (int j = 0; j < vexnum; j++) {
if (g[j][y] < closedge[j][1]) {
closedge[j][1] = g[j][y];
closedge[j][0] = y;
}
}
y = -1;
}
}
void undirected_network::print()
{
cout << endl << "最小生成树为:";
for (int i = 0; i < vexnum; i++) {
if (i != closedge[i][0]) {
cout << vexs[i] << vexs[closedge[i][0]];
}
cout << endl;
}
}
对有向图进行拓扑排序
Topological_sorting.h
#include<iostream>
#include<vector>
using namespace std;
class Topological_sorting {
private:
struct ANode {
int location; //位置信息
ANode* next;
};
struct VNode {
string name; //顶点信息
ANode* first; //头结点
VNode() {
first = new ANode;
first->location = -1;
first->next = NULL;
}
};
vector<VNode>g;
int vexnum = 0; //顶点数
int arcnum = 0; //边数
public:
void create();
void topology_sort(); //拓扑排序
bool exist(string a, int& x) {//判断顶点是否存在
x = -1;
for (unsigned int i = 0; i < g.size(); i++) {
if (a == g[i].name)x = i;
}
if (x != -1)return true;
return false;
}
bool connect(string a, string b, int x, int y) {//判断两个顶点之间是否有弧
ANode* p = g[y].first->next;
while (p != NULL) {
if (p->location == x)return true;
p = p->next;
}
return false;
}
bool arc_head(int x) {//判断该顶点是否为弧头
ANode* p = g[x].first->next;
if (p != NULL)return true;
return false;
}
};
Topological_sorting.cpp
#include "Topological_sorting.h"
void Topological_sorting::create()
{
cout << "有向图进行拓扑排序" << endl;
cout << "输入顶点数:";
cin >> vexnum;
for (int i = 0; i < vexnum; i++) {
cout << "输入第" << i + 1 << "个顶点的名称(例:a):";
VNode node;
cin >> node.name;
g.push_back(node);
}
cout << endl;
cout << "输入弧数:";
cin >> arcnum;
string a, b;
int x, y;
for (int i = 0; i < arcnum; i++) {
cout << "输入第" << i + 1 << "条弧(例:a b):";
cin >> a >> b;
if (!exist(a, x)) {
cout << "顶点" << a << "不存在" << endl;
i--;
}
else if (!exist(b, y)) {
cout << "顶点" << b << "不存在" << endl;
i--;
}
else {
if (!connect(a, b, x, y)) {
ANode* p = new ANode;
p->location = x;
p->next = g[y].first->next;
g[y].first->next = p;
}
else {
cout << "该弧已存在" << endl;
i--;
}
}
}
}
void Topological_sorting::topology_sort()
{
cout << "有向图进行拓扑排序为:" << endl;
int* v = new int[vexnum]();
int x = -1;
while (x != -2) {
//找出下一个非弧头的顶点
for (int i = 0; i < vexnum; i++) {
if (!arc_head(i) && v[i] != 1) {
x = i;
v[i] = 1;
break;
}
}
//若没找到则跳出循环
if (x == -1)x = -2;
else {
cout << g[x].name << " ";
//取消选出顶点的弧
for (int i = 0; i < vexnum; i++) {
if (i != x) {
ANode* p = g[i].first;
while (p->next != NULL) {
if (p->next->location == x) p->next = p->next->next;
if (p->next != NULL)p = p->next;
}
}
}
x = -1;
}
}
}
求AOE网的关键路径
AOE_net.h
#include<iostream>
#include<vector>
using namespace std;
class AOE_net {
private:
struct ANode {
int location; //位置信息
int weight; //权值
ANode* next;
};
struct VNode {
string name; //顶点信息
ANode* first; //头结点
VNode() {
first = new ANode;
first->location = -1;
first->next = NULL;
}
};
vector<VNode>v;
int vexnum; //顶点数
int arcnum; //边数
int* vearly;
int* vlate;
int* aearly;
int* alate;
string* arc;
public:
void create();
void aoe();
bool exist(string a, int& x) {//判断顶点是否存在
x = -1;
for (unsigned int i = 0; i < v.size(); i++) {
if (a == v[i].name)x = i;
}
if (x != -1)return true;
return false;
}
bool connect(string a, string b, int x, int y) {//判断两个顶点之间是否有弧
ANode* p = v[y].first->next;
while (p != NULL) {
if (p->location == x)return true;
p = p->next;
}
return false;
}
};
AOE_net.cpp
#include "AOE_net.h"
void AOE_net::create()
{
cout << "AOE网的关键路径" << endl;
cout << "输入顶点数:";
cin >> vexnum;
for (int i = 0; i < vexnum; i++) {
cout << "输入第" << i + 1 << "个顶点的名称(例:a):";
VNode node;
cin >> node.name;
v.push_back(node);
}
vearly = new int[vexnum]();
vlate = new int[vexnum]();
cout << endl;
cout << "输入弧数:";
cin >> arcnum;
string a, b;
int x, y, w;
for (int i = 0; i < arcnum; i++) {
cout << "输入第" << i + 1 << "条弧(例:a b 1):";
cin >> a >> b >> w;
if (!exist(a, x)) {
cout << "顶点" << a << "不存在" << endl;
i--;
}
else if (!exist(b, y)) {
cout << "顶点" << b << "不存在" << endl;
i--;
}
else {
if (!connect(a, b, x, y)) {
ANode* p = new ANode;
p->location = x;
p->weight = w;
p->next = v[y].first->next;
v[y].first->next = p;
}
else {
cout << "该弧已存在" << endl;
i--;
}
}
}
aearly = new int[arcnum]();
alate = new int[arcnum]();
arc = new string[arcnum]();
}
void AOE_net::aoe() {
//找各顶点的最早开始时间
for (int i = 0; i < vexnum; i++) {
ANode* p = v[i].first->next;
if (p == NULL)vearly[i] = 0;
else {
int z = -1;
while (p != NULL) {
if (z < p->weight + vearly[p->location])z = p->weight + vearly[p->location];
if (p != NULL)p = p->next;
}
vearly[i] = z;
}
}
//找各顶点的最晚开始时间
for (int i = 0; i < vexnum; i++)vlate[i] = -1;
vlate[vexnum - 1] = vearly[vexnum - 1];
for (int j = vexnum - 1; j >= 0; j--) {
ANode* p = v[j].first->next;
while (p != NULL) {
if (vlate[p->location] == -1)vlate[p->location] = vlate[j] - p->weight;
else if (vlate[p->location] > vlate[j] - p->weight)vlate[p->location] = vlate[j] - p->weight;
if (p != NULL)p = p->next;
}
}
//找关键路径
int x = 0;
for (int i = 0; i < vexnum; i++) {
ANode* p = v[i].first->next;
while (p != NULL) {
string a = v[p->location].name + v[i].name;
arc[x] = "边" + a;
aearly[x] = vearly[p->location];
alate[x++] = vlate[i] - p->weight;
if (p != NULL)p = p->next;
}
}
cout << endl;
cout << "关键路径为:";
//输出关键路径
for (int i = 0; i < arcnum; i++) {
if (aearly[i] == alate[i]) {
cout << arc[i] << " ";
}
}
cout << endl;
}
求单源点出发的最短路径
shortest_path.h
#include<iostream>
#include<vector>
using namespace std;
const int MAX = 9999;
class shortest_path {
private:
int vexnum; //顶点数
int arcnum; //边数
struct rectangle {
string** p;
int** d;
};
int** g;
string** p;
rectangle* D;
vector<string>vexs;
public:
void create(); //创建
void Floyd(); //计算最短路径
void print();
bool exist(string a, int& z) { //判断该点是否在d中,若在则为真
for (unsigned int i = 0; i < vexs.size(); i++) {
if (a == vexs[i])z = i;
}
if (z == -1)return false;
return true;
}
int min(int a, int b) {
if (a < b)return a;
return b;
}
};
shortest_path.cpp
#include "shortest_path.h"
void shortest_path::create()
{
cout << "单源点出发的最短路径" << endl;
string a, b; int w;
cout << "输入顶点数:";
cin >> vexnum;
g = new int* [vexnum];
p = new string * [vexnum];
for (int i = 0; i < vexnum; i++) {
cout << "输入第" << i + 1 << "个顶点名称(例:a):";
cin >> a;
vexs.push_back(a);
}
for (int i = 0; i < vexnum; i++) {
g[i] = new int[vexnum];
p[i] = new string[vexnum];
for (int j = 0; j < vexnum; j++) {
if (i == j)g[i][j] = 0;
else {
g[i][j] = MAX;
}
p[i][j] = "#";
}
}
cout << endl;
cout << "输入边数:";
cin >> arcnum;
int z1 = -1; int z2 = -1;
for (int i = 0; i < arcnum; i++) {
cout << "输入第" << i + 1 << "条边的信息(顶点1 顶点2 权重)(例:a b 1):";
cin >> a >> b >> w;
if (!exist(a, z1)) {
cout << endl << "顶点" << a << "不存在" << endl;
i--;
}
else if (!exist(b, z2)) {
cout << endl << "顶点" << b << "不存在" << endl;
i--;
}
else {
if (g[z1][z2] != MAX) {
cout << endl << "该边已存在!";
i--;
}
else {
g[z1][z2] = w;
p[z1][z2] = a + b;
}
z1 = -1; z2 = -1;
}
}
}
void shortest_path::Floyd()
{
D = new rectangle[vexnum]();
for (int i = 0; i < vexnum; i++) {
D[i].d = new int* [vexnum];
D[i].p = new string * [vexnum];
for (int j = 0; j < vexnum; j++) {
D[i].d[j] = new int[vexnum];
D[i].p[j] = new string[vexnum];
}
}
for (int i = 0; i < vexnum; i++)
for (int j = 0; j < vexnum; j++) {
D[0].d[i][j] = g[i][j];
D[0].p[i][j] = p[i][j];
}
for (int i = 0; i < vexnum; i++) {
for (int j = 0; j < vexnum; j++) {
for (int k = 0; k < vexnum; k++) {
if (j != k) {
if (i == 0) {
if (g[j][0] + g[0][k] >= g[j][k]) {
D[0].d[j][k] = g[j][k];
}
else {
D[0].d[j][k] = g[j][0] + g[0][k];
if (p[j][k] == "#") {
D[0].p[j][k] = "";
D[0].p[j][k] = vexs[j] + vexs[0] + vexs[k];
}
else {
string s1 = "";
for (unsigned int x = 0; x < p[j][0].size() - 1; x++) {
s1 += p[j][0][x];
}
unsigned y1 = vexs[0].size()-1;
while (s1[s1.size() - 1] == vexs[0][y1]) {
s1.pop_back();
y1--;
if (y1 > vexs[i].size() ||s1.size()==0)break;
}
unsigned int y2 = 0;
string s2 = "";
while (p[0][k][y2] == vexs[0][y2]) {
y2++;
if (y2 == vexs[0].size()||y2==p[0][k].size())break;
}
for (y2; y2 < p[0][k].size(); y2++) {
s2 += p[0][k][y2];
}
D[0].p[j][k] = s1 + vexs[0] + s2;
}
}
}
else {
if (D[i - 1].d[j][i] + D[i - 1].d[i][k] >= D[i - 1].d[j][k]) {
D[i].d[j][k] = D[i - 1].d[j][k];
}
else {
D[i].d[j][k] = D[i - 1].d[j][i] + D[i - 1].d[i][k];
if (D[i].p[j][k] == "#") {
D[i].p[j][k] = "";
D[i].p[j][k] = vexs[j] + vexs[i] + vexs[k];
}
else {
string s1 = "";
for (unsigned int x = 0; x < D[i - 1].p[j][i].size(); x++) {
s1 += D[i - 1].p[j][i][x];
}
unsigned int y1 = vexs[i].size() - 1;
while (s1[s1.size() - 1] == vexs[i][y1]) {
s1.pop_back();
y1--;
if (y1 > vexs[i].size()||s1.size()==0)break;
}
unsigned int y2 = 0;
string s2 = "";
while (D[i - 1].p[i][k][y2] == vexs[i][y2]) {
y2++;
if (y2 == vexs[i].size()||y2== D[i - 1].p[i][k].size())break;
}
for (y2; y2 < D[i - 1].p[i][k].size(); y2++) {
s2 += D[i - 1].p[i][k][y2];
}
D[i].p[j][k] = s1 + vexs[i] + s2;
}
}
}
}
}
}
if (i != vexnum - 1) {
for (int m = 0; m < vexnum; m++)
for (int n = 0; n < vexnum; n++) {
D[i + 1].d[m][n] = D[i].d[m][n];
D[i + 1].p[m][n] = D[i].p[m][n];
}
}
}
}
void shortest_path::print() {
cout << endl;
string a, b, c;
int z1 = -1, z2 = -1;
while (1) {
cout << "是否查询单源点出发的最短路径(y or n):";
cin >> a;
if (a == "y") {
cout << "输入两个顶点(例:a b):";
cin >> b >> c;
if (!exist(b, z1)) {
cout << endl << "顶点" << b << "不存在";
}
else if (!exist(c, z2)) {
cout << endl << "顶点" << c << "不存在";
}
else {
if (D[vexnum - 1].d[z1][z2] != MAX||D[vexnum-1].p[z1][z2]!="#") {
cout << "最短路径为:" << D[vexnum - 1].p[z1][z2] << endl;
cout << "最短路径长为:" << D[vexnum - 1].d[z1][z2] << endl;
}
else {
cout << "无法到达" << endl;
}
}
}
else if (a == "n")break;
else {
cout << "error" << endl;
char ch;
while (1) {
cin.get(ch);
if (ch == '\n')break;
}
}
}
}