Ⅰ.功能:
1.创建图
2.展示全图
3.添加顶点
4.添加边
5.删除顶点
6.删除边
7.查看指定边权值
8.修改指定边权值
9.输出两点间的所有简单路及路径对应权值
10.销毁图
ps:关于9,如果不存在任何简单路,输出“不存在任何简单路”。简单路:不含重复顶点的路。如
1 2 3 4 5是简单路,1 2 3 1 4 5不是简单路。可以想见,对于大多数问题,非简单路是没有
研究意义的。如从北京到上海的路线,多次经过同一地点的路线是没有研究价值的。
Ⅱ.不足:
1.代码冗长,复用率低。原因是有些操作基本相同但又有细微不同(如goto mark6;goto
mark7;),难以封装成一个函数。在此请求大神给出好的解决办法。
2.类的成员函数的实现也写在了头文件中,使头文件过长。原因是前几次代码使用了模板,(看
过在下前几篇博文的读者应该知道)而用模板的话,就要求要么将类的成员函数的实现和类放
在一起,要么放在main函数中(尽管听有人说《C++Primer》中说不这样也行,但在下实测的
结果是——必须这样)。在下写习惯了,写完后才发现对于此次代码,将类的成员函数的实现
另放一个文件好。但代码已经写完,就暂时不改了,万一再改出bug来,没准又得调半天,这里
和大家说一声,求原谅。
3.使用了goto语句(前几次也一样),有人对goto严格禁止,但依在下愚见,小范围内使用还是
可以的,再说,在下也是迫不得已,实在没有更好的办法了。还是那句话,求大神指教。
4.时空复杂性较高,特别是时间复杂性,懂这方面的读者一看在下的代码便知。主要是顶点和边
都是用链表实现的,动不动就要遍历,但话说回来,至今在下还没找到比用链表实现更好的方
法,还请高人指教。
Ⅲ.优点:
1.程序在多处用了控制,保证了程序的健壮性和友好,可重复操作,体验良好。
2.仅提供Operate()函数一个接口,较大限度地实现了封装。
Ⅳ.博主推荐
1.找两点间所有简单路并输出路径总权值有一定思维量和技巧性,有兴趣的读者可自行分析相
关代码,体会其思想。此代码为本人原创(当然不排除读者在其它地方见到相似代码,尽管在
下未参考任何书籍或网络资源)。
Ⅴ.代码:
//.h文件
#ifndef GRAPH_H
#define GRAPH_H
#include<iostream>
#include<iomanip>
using namespace std;
struct Edge //边结构体
{
int egnum; //结点编号
int weight; //权值
Edge* enext; //下一边结点
Edge(int enm, int wgt, Edge* enxt);
};
Edge::Edge(int enm, int wgt, Edge* enxt) //边结构体构造函数
{
egnum = enm;
weight = wgt;
enext = enxt;
}
struct Vertices //顶点结构体
{
int number; //结点编号
Edge* state; //顶点状态,用于标记顶点是否被遍历
Edge* eghead; //边链表头结点
Vertices* vnext; //下一顶点结点
Vertices(int num,Edge* sta, Edge* eghed, Vertices* vnxt);
};
Vertices::Vertices(int num,Edge* sta,Edge* eghed, struct Vertices* vnxt) //顶点结构体构造函数
{
number = num;
state = sta;
eghead = eghed;
vnext = vnxt;
}
class Graph //图类
{
private:
int vsize; //记录顶点个数
int esize; //记录边个数
Vertices* vhead; //顶点链表头指针
Vertices* vtail; //顶点链表尾指针
public:
Graph();
~Graph();
void Operate(); //封装操作
private:
Vertices* Revads(const int num); //返回某顶点地址,同时用于检测某顶点是否存在
int Creat(); //创建图
Edge* IfEdge(const int vfrom, const int vto); //查看两顶点间是否存在边
bool Addvt(); //添加顶点
int Addeg(); //添加边
void ShowAll(); //展示全图
int Getweit(const int vfrom, const int vto); //查看指定边权值
bool FinRoad(const int vfrom, const int vto); //查找两点间所有简单路
void Destory(); //销毁图
};
Graph::Graph() //图类构造函数
{
vsize = 0;
esize = 0;
vhead = NULL;
vtail = NULL;
}
Graph::~Graph() //图类析构函数
{
Destory();
}
Vertices* Graph::Revads(const int num) //返回某顶点地址,同时用于检测某顶点是否存在
{
Vertices* pt = vhead; bool flag = false;
while (pt)
{
if (pt->number == num){ flag = true; break; }
pt = pt->vnext;
}
if (flag)return pt;
else return NULL;
}
Edge* Graph::IfEdge(const int vfrom, const int vto) //查看两顶点间是否存在边
{
Vertices* pt = Revads(vfrom);
Edge* pte = pt->eghead;
while (pte)
{
if (pte->egnum == vto)
{
return pte;
}
pte = pte->enext;
}
return NULL;
}
bool Graph::Addvt() //添加顶点
{
cout << "请您输入要添加顶点的个数,程序将自动从当前图中顶点的最大编号往下顺次为新添加顶点编号:" << endl;
int sum; cin >> sum;
int itnum = vtail->number + 1;
int begin = itnum;
for (int i = 0; i < sum;i++)
{
vtail->vnext = new Vertices(itnum, NULL, NULL, NULL);
if (!vtail->vnext){ cout << "申请空间失败!" << endl; return false; }
vtail = vtail->vnext;
itnum++;
vsize++;
}
cout << "顶点添加成功!" << endl;
cout << "新顶点编号从" << begin << "到" << itnum-1 << ",目前图中共有顶点" << vsize << "个。" << endl;
cout << "当前新顶点为孤立顶点,建议您通过选项4添加指向新顶点的边和由新顶点发出的边。" << endl;
return true;
}
int Graph::Addeg() //添加边
{
cout << "提示:" << endl;
cout << "输入时,请您依次输入边的起点编号、终点编号和边的权值,中间以空格相隔,例如:1 2 20。并且,请您务必输入正整数,";
cout << "如果您未按规定输入,由此造成的一切后果,将由您个人承担,程序开发者概不负责!" << endl;
bool sign = true, flag = true;
int from, to, weit, choice, abandon,abandon1,abandon2; //标签
Vertices* pt=NULL;
while (sign)
{
while (flag)
{
abandon = 0; abandon1 = 0; abandon2 = 0; //只要重新输入,就要进行一次初始化
cout << "请您依次输入边的起点、终点和权值:" << endl;
cin>> from >> to >> weit;
if (from == to) //如果起、止点相同,不进行进一步检查,直接进行选择
{
cout << "起点编号与终点编号不得相同!重新输入请按1,放弃本次输入请按0:" << endl;
cin >> choice;
if (choice == 0){ abandon1 = 1; abandon = 1; }
else { abandon1 = 1; flag = false; }
}
if (!abandon1) //如果起、止点不同,检查起、止点是否正确及两点间是否有边
{
pt = Revads(from);
if (!pt) //如果起点不存在,不进行进一步检查,直接进行选择
{
cout << "您输入的起点不存在!重新输入请按1,放弃本次输入请按0:" << endl;
cin >> choice;
if (choice == 0){ abandon2 = 1; abandon = 1; }
else { abandon2 = 1; flag = false; }
}
else //如果起点存在,检查终点,若果终点不存在,不进行进一步检查,直接进行选择
{
if (!Revads(to))
{
cout << "您输入的终点不存在!重新输入请按1,放弃本次输入请按0:" << endl;
cin >> choice;
if (choice == 0){ abandon2 = 1; abandon = 1; }
else { abandon2 = 1; flag = false; }
}
}
if (!abandon2)//如果两点输入正确且都存在,检查两点间是否有边,若无,进行选择
{
Edge* ifedge = IfEdge(from, to);
if (ifedge)
{
cout << "从顶点" << from << "到顶点" <