项目名称:通信网构建 项目内容:
在 n 个城市之间建立通信联络网,则连通 n 个城市只需要 n-1 条线路。
要求在 最节省经费的前提下建立这个通信网。
(1) 完成城市信息的输入。
(2) 完成城市信息的编辑,包括城市以及城市间距离的增加,删除,信息修改等。
(3) 允许用户指定下列两种策略进行通信网的构建
1.采用 Prim 算法进行通信网的构建;
2.采用 Kruskal 算法进行通信网的构建;
main函数:
#include
#include
#include"Graph.h"
#include"SqList.hpp"
using namespace std;
void test01(Graph* graph) {
//输入测试数据
Vex v1; v1.code = "V1"; v1.Name = "北京";
Vex v2; v2.code = "V2"; v2.Name = "成都";
Vex v3; v3.code = "V3"; v3.Name = "武汉";
Vex v4; v4.code = "V4"; v4.Name = "上海";
Vex v5; v5.code = "V5"; v5.Name = "广州";
Vex v6; v6.code = "V6"; v6.Name = "深圳";
graph->InsertVex(v1);
graph->InsertVex(v2);
graph->InsertVex(v3);
graph->InsertVex(v4);
graph->InsertVex(v5);
graph->InsertVex(v6);
Edge e1; e1.vex1 = v1; e1.vex2 = v2; e1.weight = 6;
Edge e2; e2.vex1 = v1; e2.vex2 = v3; e2.weight = 1;
Edge e3; e3.vex1 = v1; e3.vex2 = v4; e3.weight = 5;
Edge e4; e4.vex1 = v2; e4.vex2 = v3; e4.weight = 5;
Edge e5; e5.vex1 = v2; e5.vex2 = v5; e5.weight = 3;
Edge e6; e6.vex1 = v3; e6.vex2 = v4; e6.weight = 5;
Edge e7; e7.vex1 = v3; e7.vex2 = v5; e7.weight = 6;
Edge e8; e8.vex1 = v3; e8.vex2 = v6; e8.weight = 4;
Edge e9; e9.vex1 = v4; e9.vex2 = v6; e9.weight = 2;
Edge e10; e10.vex1 = v5; e10.vex2 = v6; e10.weight = 6;
graph->InsertEdges(e1);
graph->InsertEdges(e2);
graph->InsertEdges(e3);
graph->InsertEdges(e4);
graph->InsertEdges(e5);
graph->InsertEdges(e6);
graph->InsertEdges(e7);
graph->InsertEdges(e8);
graph->InsertEdges(e9);
graph->InsertEdges(e10);
cout << "添加成功" << endl;
system("pause");
}
int main() {
Graph *graph = new Graph();
Edge a[10];
while (1) {
system("cls");
cout << "1.测试案例" << endl;
cout << "2.添加顶点" << endl;
cout << "3.添加边" << endl;
cout << "4.prim算法" << endl;
cout << "5.kruskal算法" << endl;
cout << "6.删除修改信息" << endl;
cout << "7.打印顶点和边的信息" << endl;
cout << "8.退出" << endl;
int m;
cin >> m;
switch (m) {
case 1: {
test01(graph);
break;
}
case 2: {
cout << "输入要添加的顶点数:" << endl;
int n = 0;
cin >> n;
for (int i = 0; i < n; i++) {
Vex v;
cout << "输入顶点编号" << endl;
cin >> v.code;
cout << "输入顶点名称" << endl;
cin >> v.Name;
graph->InsertVex(v);
}
break;
}
case 3: {
cout << "输入要添加的边数:" << endl;
int n = 0;
cin >> n;
for (int i = 0; i < n; i++) {
Edge e;
cout << "输入边的一个顶点" << endl;
cin >> e.vex1.code;
cout << "输入另一个顶点" << endl;
cin >> e.vex2.code;
cout << "输入权值" << endl;
cin >> e.weight;
graph->InsertEdges(e);
}
break;
}
case 4: {
graph->PrimMinTree(a);
system("pause");
break;
}
case 5: {
graph->KruskalMinTree(a);
system("pause");
break;
}
case 6: {
cout << "1.修改顶点" << endl;
cout << "2.删除顶点" << endl;
cout << "3.修改边" << endl;
cout << "4.删除边" << endl;
int m;
cin >> m;
if (m == 1) {
Vex a;
cout << "输入修改的顶点的编号" << endl;
cin >> a.code;
cout << "输入修改的顶点的名称" << endl;
cin >> a.Name;
graph->UpdateVex(a);
}
else if (m == 2) {
Vex b;
cout << "输入修改的顶点的编号" << endl;
cin >> b.code;
graph->DeleteVex(b);
}
else if (m == 3) {
Edge c;
cout << "输入修改边的第一个顶点编号" << endl;
cin >> c.vex1.code;
cout << "输入修改边的第二个顶点编号" << endl;
cin >> c.vex2.code;
cout << "输入修改边的权值" << endl;
cin >> c.weight;
graph->UpdateEdges(c);
}
else if (m == 4) {
Edge d;
cout << "输入修改边的第一个顶点编号" << endl;
cin >> d.vex1.code;
cout << "输入修改边的第二个顶点编号" << endl;
cin >> d.vex2.code;
graph->DeleteEdges(d);
}
else {
cout << "输入错误" << endl;
}
system("pause");
break;
}
case 7: {
graph->showMassage();
system("pause");
break;
}
case 8: {
return 0;
break;
}
}
}
}
图的头文件声明Graph.h:
#pragma once
#define numMAX 20
#define StrMAX 100
#define MAX 1000
#include
#include
#include"SqList.hpp"
#include
using namespace std;
//节点结构体
struct Vex {
string code;
string Name;
};
//边结构体
struct Edge {
Vex vex1;
Vex vex2;
int weight=-1;
};
class Graph {
private:
int AdjMatrix[numMAX][numMAX];//邻接矩阵
SqList<Vex>Vexs; //点的集合
SqList<Edge>Edges; //边的集合
int VexNum; //点的个数
public:
Graph();
~Graph();
bool InsertVex(Vex svex); //增加节点
bool DeleteVex(Vex svex); //删除节点
bool UpdateVex(Vex svex); //更新节点
bool InsertEdges(Edge sedge); //增加边
bool DeleteEdges(Edge sedge); //删除边
bool UpdateEdges(Edge sedge); //更新边
Edge GetEdge(char* vex1Code, char* vex2Code);//得到边
Vex GetVex(char*vex1Code); //得到点
void SetVexNum(int); //更新节点数
int PrimMinTree(Edge aPath[]); //prim算法实现最小生成树
int KruskalMinTree(Edge aPath[]); //kruskal算法实现最小生成树
void showMassage(); //打印顶点和边的信息
private:
bool isConnect(Edge b,Edge outEdges[],int n);
};
头文件的实现Graph.cpp
#include"Graph.h"
Graph::Graph(){
for (int i = 0; i < numMAX; i++) {
for (int j = 0; j < numMAX; j++) {
if (i == j)
this->AdjMatrix[i][j] = 0;
else
this->AdjMatrix[i][j] = 10000;
}
}
this->VexNum = 0;
}
Graph::~Graph() {
}
bool Graph::InsertVex(Vex svex) {
for (int i = 0; i < this->Vexs.GetLength(); i++) {
Vex a;
this->Vexs.GetElem(i, a);
if (a.code == svex.code && a.Name == svex.Name)
cout << "顶点存在" << endl;
}
if (this->VexNum < numMAX) {
this->Vexs.InsertElem(svex);
this->VexNum++;
return 1;
}
else {
cout << "顶点达到最大容量" << endl;
return 0;
}
}
bool Graph::DeleteVex(Vex svex) {
int sign = 0;
Vex a;
for (int i = 0; i < this->Vexs.GetLength(); i++) {
this->Vexs.GetElem(i, a);
if (a.code._Equal(svex.code)) {
this->Vexs.DeleteElem(i, a);
this->VexNum--;
sign = 1;
break;
}
}
for (int m = 0; m < this->Edges.GetLength(); m++) {
Edge e;
this->Edges.GetElem(m, e);
if (e.vex1.code._Equal(a.code) | a.code._Equal(e.vex2.code)) {
Edges.DeleteElem(m, e);
m--;
int p = (int)(e.vex1.code[1] - '0');
int n = (int)(e.vex2.code[1] - '0');
this->AdjMatrix[p][n] = 1000;
this->AdjMatrix[n][p] = 1000;
}
}
if (sign == 0)
return 0;
else
return 1;
}
bool Graph::UpdateVex(Vex svex) {
int sign = 0;
Vex a;
for (int i = 0; i < this->Vexs.GetLength(); i++) {
this->Vexs.GetElem(i, a);
if (a.code == svex.code) {
this->Vexs.SetElem(i, svex);
sign = 1;
break;
}
}
if (sign == 0)
return 0;
else
return 1;
}
bool Graph::InsertEdges(Edge sedge) {
int sign = 0;
Edge a;
for (int i = 0; i < this->Edges.GetLength(); i++) {
this->Edges.GetElem(i, a);
if (a.vex1.code == sedge.vex1.code && a.vex2.code == sedge.vex2.code)
sign = 1;
if (a.vex1.code == sedge.vex2.code && a.vex2.code == sedge.vex2.code)
sign = 1;
}
if (sign == 0) {
this->Edges.InsertElem(sedge);
int m = (int)(sedge.vex1.code[1] - '0');
int n = (int)(sedge.vex2.code[1] - '0');
this->AdjMatrix[m][n] = sedge.weight;
this->AdjMatrix[n][m] = sedge.weight;
return 1;
}
else {
cout << "这条边已经存在" << endl;
return 0;
}
}
bool Graph::DeleteEdges(Edge sedge) {
int sign = 0;
Edge a;
for (int i = 0; i < this->Edges.GetLength(); i++) {
this->Edges.GetElem(i, a);
if ((a.vex1.code == sedge.vex1.code && a.vex2.code == sedge.vex2.code)
|| (a.vex1.code == sedge.vex2.code && a.vex2.code == sedge.vex2.code)) {
Edges.DeleteElem(i, a);
sign = 1;
}
}
if (sign == 1) {
int m = (int)(sedge.vex1.code[1] - '0');
int n = (int)(sedge.vex2.code[1] - '0');
this->AdjMatrix[m][n] = 1000;
this->AdjMatrix[n][m] = 1000;
cout << "删除成功" << endl;
return 1;
}
else {
cout << "这条边不存在" << endl;
return 0;
}
}
bool Graph::UpdateEdges(Edge sedge) {
int sign = 0;
Edge a;
for (int i = 0; i < this->Edges.GetLength(); i++) {
this->Edges.GetElem(i, a);
if ((a.vex1.code == sedge.vex1.code && a.vex2.code == sedge.vex2.code)
|| (a.vex1.code == sedge.vex2.code && a.vex2.code == sedge.vex2.code)) {
Edges.SetElem(i, sedge);
sign = 1;
}
}
if (sign == 1) {
cout << "更新成功" << endl;
return 1;
}
else {
cout << "更新失败" << endl;
return 0;
}
}
Edge Graph::GetEdge(char* vex1Code, char* vex2Code) {
int sign = 0;
Edge a;
for (int i = 0; i < this->Edges.GetLength(); i++) {
this->Edges.GetElem(i, a);
if ((a.vex1.code[1] ==*vex1Code && a.vex2.code[1] ==*vex2Code)
|| (a.vex1.code[1] == *vex2Code && a.vex2.code[1] == *vex2Code)) {
Edges.GetElem(i, a);
sign = 1;
}
}
if (sign == 0) {
return a;
}
else {
cout << "查找失败" << endl;
return a;
}
}
Vex Graph::GetVex(char* vex1Code) {
int sign = 0;
Vex a;
for (int i = 0; i < this->Vexs.GetLength(); i++) {
this->Vexs.GetElem(i, a);
if (a.code[1] == *vex1Code) {
Vexs.GetElem(i, a);
sign = 1;
}
}
if (sign == 0) {
return a;
}
else {
cout << "查找失败" << endl;
return a;
}
}
void Graph::SetVexNum(int) {
this->VexNum = Vexs.GetLength();
}
int Graph::PrimMinTree(Edge aPath[]) {
cout << "prim算法实现最小生成树" << endl;
//从第一个点出发
int x = 1;
//记录他的链接顶点
int closest[numMAX];
//记录最短边
int min;
//记录链接点上的权值
int lowcost[numMAX];
//数组初始化
for (int i = 1; i <= this->VexNum; i++) {
lowcost[i] = AdjMatrix[x][i];
closest[i] = x;
}
int i = 1;
int j;
int k;
for (j = 2; j <= this->VexNum; j++) {
min = 10000;
for (k = 1; k <= this->VexNum; k++) {
if ((lowcost[k] < min) && (lowcost[k] != 0)) {
min = lowcost[k];
i = k;
}
}
lowcost[i] = 0;
for (k = 1; k <= this->VexNum; k++) {
if (lowcost[k] > AdjMatrix[k][i]) {
lowcost[k] = AdjMatrix[k][i];
closest[k] = i;
}
}
}
for (j = 2; j <= this->VexNum; j++) {
cout << "v"<<j << "-" << "v"<<closest[j] << endl;
}
return 0;
}
int Graph::KruskalMinTree(Edge aPath[]) {
cout << "Kruskal算法实现最小生成树" << endl;
//取出边
Edge mEdges[MAX];
int numEdges = this->Edges.GetLength();
for (int i = 0; i < numEdges; i++) {
Edges.GetElem(i, mEdges[i]);
}
//把边按从小到大排列
for (int i = 0; i < numEdges; i++) {
for (int j = 0; j < numEdges - 1; j++) {
Edge a;
if (mEdges[j].weight > mEdges[j + 1].weight) {
a = mEdges[j];
mEdges[j] = mEdges[j + 1];
mEdges[j + 1] = a;
}
}
}
//定义一个边数组
Edge outEdges[MAX];
//记录合格的边
int outNumber = 0;
int numberEdges = 0;
//循环判断合格边并加入
while (outNumber < this->VexNum-1&&numberEdges<=this->Edges.GetLength()) {
outEdges[outNumber] = mEdges[numberEdges];
outNumber++;
if (isConnect(mEdges[numberEdges], outEdges,outNumber)) {
outNumber--;
}
numberEdges++;
}
//达标输出,不达标则不输出
if (outNumber == this->Vexs.GetLength() - 1) {
for (int i = 0; i < outNumber; i++) {
cout<<outEdges[i].vex1.code << "-" << outEdges[i].vex2.code << "权值:" << outEdges[i].weight << endl;
}
}
else {
cout << "这些边构不成一颗最小生成树" << endl;
}
return 0;
}
bool Graph::isConnect(Edge b, Edge outEdges[], int n) {
typedef struct d {
Vex a;
int num=0;
}D;
D d[MAX];
int sumD = 0;
//统计顶点和度
for (int i = 0; i < n; i++) {
int sign = 0;
int sign2 = 0;
for (int j = 0; j < sumD; j++) {
if (d[j].a.code == outEdges[i].vex1.code) {
d[j].num++;
sign = 1;
}
if (d[j].a.code == outEdges[i].vex2.code) {
d[j].num++;
sign2 = 1;
}
}
if (sign == 0) {
d[sumD].a.code = outEdges[i].vex1.code;
d[sumD].a.Name = outEdges[i].vex1.Name;
d[sumD].num++;
sumD++;
}
if (sign2 == 0) {
d[sumD].a.code = outEdges[i].vex2.code;
d[sumD].a.Name = outEdges[i].vex2.Name;
d[sumD].num++;
sumD++;
}
}
//利用拓扑排序判断是否有环路
while (1) {
//判断是否结束循环
int sign = 0;
for (int i = 0; i < sumD; i++) {
if (d[i].num == 1)
sign = 1;
}
if (sign == 0) {
if (sumD == 0||sumD==1)
return 0;
else
return 1;
}
else {
for (int j = 0; j < sumD; j++) {
if (d[j].num == 1) {
for (int m = 0; m < n; m++) {
if (outEdges[m].vex1.code == d[j].a.code) {
for (int p = 0; p < sumD; p++) {
if (d[p].a.code == outEdges[m].vex2.code)
d[p].num--;
}
}
if (outEdges[m].vex2.code == d[j].a.code) {
for (int p = 0; p < sumD; p++) {
if (d[p].a.code == outEdges[m].vex1.code)
d[p].num--;
}
}
}
for (int p = j; p < sumD-1; p++) {
d[p] = d[p + 1];
}
sumD--;
}
}
//去掉度为0的顶点
for (int q = 0; q < sumD; q++) {
if (d[q].num == 0) {
for (int k = q; k < sumD - 1; k++) {
d[k] = d[k + 1];
}
sumD--;
}
}
}
}
}
void Graph::showMassage() {
cout << "顶点信息:" << endl;
for (int i = 0; i < this->Vexs.GetLength(); i++) {
Vex a;
this->Vexs.GetElem(i, a);
cout << a.code << "--" << a.Name << endl;
}
cout << "边信息:" << endl;
for (int j = 0; j < this->Edges.GetLength(); j++) {
Edge b;
this->Edges.GetElem(j, b);
cout << b.vex1.code << "--" << b.vex2.code << "权值:" << b.weight << endl;
}
}
栈的实现SqList.hpp
#pragma once
#ifndef __SQ_LIST_H__
#endif
#define __SQ_LIST_H__
// ANSI C++标准库头文件
#include // 标准串操作
#include // 标准流操作
using namespace std;
// 宏定义
#define DEFAULT_SIZE 1000 // 缺省元素个数
#define DEFAULT_INFINITY 1000000 // 缺省无穷大
// 顺序表模板类的申明
template <class ElemType>
class SqList
{
protected:
// 顺序表的数据成员
int length; // 顺序表的当前长度
int maxLength; // 顺序表的最大容量
ElemType* data; // 元素存储空间的首地址
public:
// 顺序表的函数成员
SqList(int size = DEFAULT_SIZE); // 构造一个空表
virtual ~SqList(); // 析构函数
int GetLength() const; // 取顺序表长度
int GetElem(int i, ElemType& e) const; // 取顺序表中第i个元素的值
int SetElem(int i, const ElemType& e); // 修改顺序表中第i个元素的值
int DeleteElem(int i, ElemType& e); // 删除顺序表中第i个元素
int InsertElem(const ElemType& e); // 在顺序表表尾插入元素
};
// 构造一个空表
template<class ElemType>
SqList<ElemType>::SqList(int size) {
this->length = 0;
this->maxLength = size;
data = new ElemType[DEFAULT_SIZE];
}
// 析构函数
template<class ElemType>
SqList<ElemType>::~SqList() {
}
// 取顺序表长度
template<class ElemType>
int SqList<ElemType>::GetLength() const {
return this->length;
}
// 取顺序表中第i个元素的值
template<class ElemType>
int SqList<ElemType>::GetElem(int i, ElemType& e) const {
if ((i<this->length)&&i>=0)
e = data[i];
else
cout << "没有找到" << endl;
return 0;
}
// 修改顺序表中第i个元素的值
template<class ElemType>
int SqList<ElemType>::SetElem(int i, const ElemType& e) {
if ((i < this->length) && i >= 0)
this->data[i] = e;
else
cout << "没有找到" << endl;
return 0;
}
// 删除顺序表中第i个元素
template<class ElemType>
int SqList<ElemType>::DeleteElem(int i, ElemType& e) {
e = this->data[i];
if ((i < this->length) && i >= 0) {
for (int j = i; j < this->length - 1; j++)
this->data[j] = this->data[j + 1];
this->length--;
}
else
cout << "没有找到" << endl;
return 0;
}
// 在顺序表表尾插入元素
template<class ElemType>
int SqList<ElemType>::InsertElem(const ElemType& e) {
this->data[this->length] = e;
this->length++;
return 0;
}