基于图的邻接链表和邻接矩阵实现图的各种常用函数
图最常用的表示方法有邻接链表和邻接矩阵;图的常见函数包括图的建立和销毁,边的插入删除,图的深度优先和广度优先遍历,最小生成树,最短路径等。下面代码在邻接链表和邻接矩阵的基础上分别实现了函数,其中类Graph 是邻接链表表示的,GraphM是邻接矩阵表示的。这里代码比较多,原因是有可能存在多个版本或者多种实现方法。不多说啦,直接上代码。
文件main.cpp
/*
* 文件 main.cpp
* 功能 示例
* 作者 lmjy
* 日期 2017/5/27
*
*/
#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <queue>
#include "graph.h"
using namespace std;
int main(){
Graph g1(ifstream("g.txt"), 5, 10);
//GraphM g1(ifstream("g.txt"),5, 10);
cout << "输出图: " << endl;
g1.print();
cout << endl;
cout << "深度遍历0: " << g1.dfs1(0) << endl;
cout << "深度遍历3: " << g1.dfs2(3) << endl;
cout << "广度遍历4: " << g1.bfs(4) << endl;
cout << "最小生成树: " << g1.mstPrim() << endl;
cout << "最小生成树: " << g1.mstKruskal() << endl;
cout << "BF最短路径(0,2)" << g1.shortestPathBF(0, 2) << endl;
cout << "DJ最短路径(0,2)" << g1.shortestPathDijkstra(0, 2) << endl;
cout << "BF最短路径(2,0)" << g1.shortestPathBF(2, 0) << endl;
cout << "DJ最短路径(2,0)" << g1.shortestPathDijkstra(2, 0) << endl;
cout << "BF最短路径(1,4)" << g1.shortestPathBF(1, 4) << endl;
cout << "DJ最短路径(1,4)" << g1.shortestPathDijkstra(1, 4) << endl;
cout << "BF最短路径(4,1)" << g1.shortestPathBF(4, 1) << endl;
cout << "DJ最短路径(4,1)" << g1.shortestPathDijkstra(4, 1) << endl;
return 0;
}
其中:图结构如图所示
根据图结构书写格式,g.txt如下
0 0 1 3
1 0 3 5
2 1 2 6
3 1 3 2
4 2 4 2
5 3 1 1
6 3 2 4
7 3 4 6
8 4 2 7
9 4 0 3
运行结果如下(Graph类):
运行结果(GraphM类):
下面是图的具体实现文件
文件 graph.h
/*
* 文件 graph.h
* 功能 图相关的类和函数的声明
* 作者 lmjy
* 日期 2017/5/27
*
*/
#ifndef GRAPH_H
#define GRAPH_H
#define PATHEV 1 // 路径集合是边还是点 1为边 0为点
#define MAXWEIGHT INT32_MAX >> 1 // 表示权值无穷大
typedef int Weight; // 权重
typedef int Status; // 状态记录
typedef int Data[1]; // 数据
struct EdgeNode { // 边结点
int eNum, headv, tailv; // 边编号, 边起点, 边终点
Weight weight; // 边权值
Status status; // 边状态
Data data{ 0 }; // 边数据
EdgeNode *nextIn, *nextOut; // 入边( 十字链表才需要 ), 出边
EdgeNode(int en = 0, int v1 = 0, int v2 = 0, Weight w = 1) // 构造函数, 边编号 起点 尾点 权值
:eNum(en), headv(v1), tailv(v2), weight(w), status(0), nextIn(nullptr), nextOut(nullptr) {}
EdgeNode(std::istream& is) : status(0), nextIn(nullptr), nextOut(nullptr) { // 输入流, 构成一条边 格式: 边编号 起点 尾点 权值
is >> eNum >> headv >> tailv >> weight;}
friend bool operator==(const EdgeNode&, const EdgeNode&); // 相等重载, 判断是否同一条边
friend bool operator!=(const EdgeNode&, const EdgeNode&); // 不等重载
friend std::ostream& operator << (std::ostream&, EdgeNode&); // 输入输出重载, 格式: 边编号 起点 尾点 权值
friend std::istream& operator >> (std::istream&, EdgeNode&);
};
bool operator==(const EdgeNode&, const EdgeNode&); // 边友元函数声明
bool operator!=(const EdgeNode&, const EdgeNode&);
std::ostream& operator<<(std::ostream&, EdgeNode&);
std::istream& operator >> (std::istream&, EdgeNode&);
struct VertexNode { // 点结点
int vNum; // 点编号
Status status; // 点状态
Data data{ 0 }; // 点数据
EdgeNode *nextIn, *nextOut; // 入边, 出边
VertexNode(int n1 = 0) :vNum(n1), status(0), nextIn(nullptr), nextOut(nullptr) {}
};
struct Path {
int vStart, vEnd; // 路径的起止点(源和目的节点)
Weight dist; // 路径总代价
std::vector<int> pathV, pathE; // 存储路径, 分别存中间点编号和边编号
Path(int v1 = 0, int v2 = 0, Weight d = 0) :vStart(v1), vEnd(v2), dist(d) {}
Path& operator+=(const Path&); // 添加路径在末端
friend Path operator+(const Path&, const Path&); // 连接两条路径
friend std::ostream& operator <<(std::ostream&, Path&); // 输出重载 格式: 起点 --> 终点 $ 代价 @ <路径>
};
Path operator+(const Path&, const Path&);
std::ostream& operator <<(std::ostream&, Path&);
struct Graph { // 图类, 邻接链表表示
int vn, en; // 顶点和边的数目
std::vector<VertexNode> adjList; // 邻接链表( 十字链表 )
Graph(int n1 = 0) :vn(n1), en(0), adjList(n1) {
for (int k1(0); k1 < n1; ++k1) adjList[k1].vNum = k1;
}
Graph(std::istream& is, int n1 = 2, int n2 = 1, bool v = true); // n1 点上限, n2 边上限, v表示有向或者无向图
~Graph();
void insert(const EdgeNode&,bool = true); // 插入一条边, v表示有向或者无向图, 默认有向
int remove(const EdgeNode&, bool = true); // 删除一条边, v表示有向或者无向图, 默认有向, 返回删除的边数
int remove(int, bool = true); // 删除一顶点相连的所有边, 返回删除的边数
void print(bool = true, std::ostream& = std::cout);
Path dfs1(int = 0); // 深度遍历递归 遍历顶点依次存在 Path 中
void dfs1(Path&, int = 0); // 深度遍历递归辅助函数
Path dfs2(int = 0); // 深度遍历迭代
Path bfs(int = 0); // 广度遍历迭代
Path mstPrim(int = 0); // 最小生成树 prim
Path mstKruskal(); // 最小生成树 Kruskal
std::vector<Path> shortestPathBF(int = 0); // 最短路径 Bellman Ford 单源
Path shortestPathBF(int, int); // 最短路径 Bellman Ford 两点
std::vector<Path> shortestPathDijkstra(int = 0); // 最短路径 Dijkstra 单源
Path shortestPathDijkstra(int, int); // 最短路径 Dijkstra 两点
};
struct GraphM { // 图类, 邻接矩阵表示
int vn;
std::vector<std::vector<Weight>> wMat; // 邻接矩阵 存储权值, 0表示无穷大
std::vector<std::vector<int>> eMat; // 边编号矩阵 存储边序号
GraphM(int n1 = 0) :vn(n1), wMat(n1, std::vector<Weight>(n1, 0)), eMat(n1, std::vector<Weight>(n1, -1)) {}
GraphM(std::istream& is, int n1 = 2, int n2 = 1, bool v = true); // n1 点上限, n2 边上限, v表示有向或者无向图
bool insert(const EdgeNode&, bool = true); // 插入一条边, v表示有向或者无向图, 默认有向
int remove(const EdgeNode&, bool = true); // 删除一条边, v表示有向或者无向图, 默认有向, 返回删除的边数
int remove(int, bool = true); // 删除一顶点相连的边, 返回删除的边数
void print(bool = true, std::ostream& = std::cout);
Path dfs1(int = 0); // 深度遍历递归 遍历顶点依次存在 Path 中
void dfs1(Path&, std::vector<int>&, int = 0); // 深度遍历递归辅助函数
Path dfs2(int = 0); // 深度遍历迭代版本
Path bfs(int = 0); // 广度遍历迭代版本
Path mstPrim(int = 0); // 最小生成树 prim
Path mstKruskal(); // 最小生成树 Kruskal
std::vector<Path> shortestPathBF(int = 0); // 最短路径 Bellman Ford 单源
Path shortestPathBF(int, int); // 最短路径 Bellman Ford 两点
std::vector<Path> shortestPathDijkstra(int = 0); // 最短路径 Dijkstra 单源
Path shortestPathDijkstra(int, int); // 最短路径 Dijkstra 两点
std::vector<std::vector<Path>> shortestPathFloyd() const; // 最短路径 Floyd 全源
Path shortestPathFloyd(int, int) const; // 最短路径 Floyd 两点
};
// 辅助函数
int findSet(std::vector<int>&, int = 0); // 集合查找, 返回集合中最后一个元素的索引
void vPass(Path&, std::vector<std::vector<int>>&, int, int); // 由节点前驱矩阵确定路径
#endif
文件 graph.cpp
/*
* 文件 graph.cpp
* 功能 图类相关的函数的实现
* 作者 lmjy
* 日期 2017/5/27
*
*/
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include "graph.h"
using namespace std;
int findSet(std::vector<int>& v, int n) {
while (v[n] != n) n = v[n]; // 迭代直至最后一个集合的元素
return n;
}
void vPass(Path& p, std::vector<std::vector<int>>& v, int v1, int v2) {
if (-1 < v[v1][v2]) { // 由节点前驱矩阵递归中间节点
vPass(p, v, v1, v[v1][v2]);
p.pathV.push_back(v[v1][v2]);
vPass(p, v, v[v1][v2], v2);
}
}
bool operator==(const EdgeNode& e1, const EdgeNode& e2) {
return e1.headv == e2.headv && e1.tailv == e2.tailv && e1.eNum == e2.eNum && e1.weight == e2.weight;
}
bool operator!=(const EdgeNode& e1, const EdgeNode& e2) {
return !(e1 == e2);
}
ostream& operator<<(ostream& os, EdgeNode& e) {
os << e.eNum << ends << e.headv << ends << e.tailv << ends << e.weight;
return os;
}
istream& operator >> (istream& is, EdgeNode& e) {
is >> e.eNum >> e.headv >> e.tailv >> e.weight;
return is;
}
Path& Path::operator+=(const Path& p) {
if (vEnd != p.vStart) return *this;
vEnd = p.vEnd;
dist += p.dist;
pathV.push_back(p.vStart);
for (const auto vi : p.pathV) pathV.push_back(vi);
for (const auto vi : p.pathE) pathE.push_back(vi);
return *this;
}
Path operator+(const Path& p1, const Path& p2) {
Path pt(p1);
pt += p2;
return pt;
}
ostream& operator <<(std::ostream& os, Path& pe) {
os << pe.vStart << " --> " << pe.vEnd << " $ " << pe.dist << " @ <";
#if PATHEV
for (size_t k1(0); k1 < pe.pathE.size(); ++k1) {
os << pe.pathE[k1];
if (k1 != pe.pathE.size() - 1) os << ", ";
}
#else
for (size_t k1(0); k1 < pe.pathV.size(); ++k1) {
os << pe.pathV[k1];
if (k1 != pe.pathV.size() - 1) os << ", ";
}
#endif
os << ">";
return os;
}
Graph::Graph(istream& is, int n1, int n2, bool v) :vn(n1), en(0), adjList(n1) {
for (int k1(0); k1 < n1; ++k1) adjList[k1].vNum = k1;
EdgeNode et;
while (en < n2 && is >> et) {
if (et.headv < vn && et.tailv < vn) insert(et, v);
}
}
Graph::~Graph() {
EdgeNode *ep(nullptr);
for (int k1(0); k1 < vn; ++k1) {
while (ep = adjList[k1].nextOut) {
adjList[k1].nextOut = ep->nextOut;
delete ep;
}
}
en = vn = 0;
adjList.clear();
}
void Graph::insert(const EdgeNode &e, bool v) {
int vn1(max(e.headv, e.tailv) + 1);
if (vn < vn1) {
adjList.resize(vn1);
for (int k1(vn); k1 < vn1; ++k1) adjList[k1].vNum = k1; // 插入新顶点
vn = vn1;
}
EdgeNode *ep = new EdgeNode(e);
ep->nextOut = adjList[ep->headv].nextOut; // 插入该边
adjList[ep->headv].nextOut = ep;
// 下面两句形成十字链表
//ep->nextIn = adjList[ep->tailv].nextIn;
//adjList[ep->tailv].nextIn = ep;
++en;
if (!v) { // 插入无向边的对称边
EdgeNode *ep = new EdgeNode(e);
swap(ep->headv, ep->tailv);
ep->nextOut = adjList[ep->headv].nextOut;
adjList[ep->headv].nextOut = ep;
// 下面两句形成十字链表
//ep->nextIn = adjList[ep->tailv].nextIn;
//adjList[ep->tailv].nextIn = ep;
}
}
int Graph::remove(const EdgeNode &e, bool v) {
if (!(e.headv < vn && e.tailv < vn && adjList[e.headv].nextOut)) return 0;
EdgeNode et(e), *ep1(nullptr), *ep2(nullptr), *ep3(nullptr);
for (ep2 = adjList[et.headv].nextOut; ep2 && *ep2 != et; ep1 = ep2, ep2 = ep2->nextOut);
if (!ep2) return 0; // 查找边是否存在
ep1 ? ep1->nextOut = ep2->nextOut : adjList[et.headv].nextOut = ep2->nextOut;
// 删除十字链表
//for(ep3 = adjList[et.tailv].nextIn; ep3 != ep2; ep1 = ep3, ep3 = ep3->nextIn);
//ep1 ? ep1->nextIn = ep3->nextIn : adjList[et.tailv].nextIn = ep3->nextIn;
delete ep2;
if (!v) { // 删除无向边的对称边
swap(et.headv, et.tailv);
for (ep2 = adjList[et.headv].nextOut; ep2 && *ep2 != et; ep1 = ep2, ep2 = ep2->nextOut);
if (!ep2) return 0;
ep1 ? ep1->nextOut = ep2->nextOut : adjList[et.headv].nextOut = ep2->nextOut;
// 删除十字链表
//for(ep3 = adjList[et.tailv].nextIn; ep3 != ep2; ep1 = ep3, ep3 = ep3->nextIn);
//ep1 ? ep1->nextIn = ep3->nextIn : adjList[et.tailv].nextIn = ep3->nextIn;
delete ep2;
}
--en; // 改变边数
return 1;
}
int Graph::remove(int vnum, bool v) {
if (!(vnum < vn)) return 0;
int ede(0);
EdgeNode *ep1(nullptr), *ep2(nullptr);
for (int k1(0); k1 < vn; ++k1) {
ep1 = nullptr;
ep2 = adjList[k1].nextOut;
while (ep2) {
if (ep2->headv == vnum || ep2->tailv == vnum) {
ep1 ? ep1->nextOut = ep2->nextOut : adjList[k1].nextOut = ep2->nextOut;
EdgeNode *ep3(nullptr), *ep4(nullptr);
// 删除十字链表
//for (ep4 = adjList[ep2->tailv].nextIn; ep4 != ep2; ep3 = ep4, ep4 = ep4->nextIn);
//ep3 ? ep3->nextIn = ep4->nextIn : adjList[ep2->tailv].nextIn = ep4->nextIn;
delete ep2;
++ede;
}
else ep1 = ep2;
ep2 = ep1 ? ep1->nextOut : adjList[k1].nextOut;
}
}
if (!v) ede >>= 1;
en -= ede;
return ede;
}
void Graph::print(bool v, std::ostream& os) {
EdgeNode *ep(nullptr);
for (int k1(0); k1 < vn; ++k1) {
adjList[k1].status = 1;
}
for (int k1(0); k1 < vn; ++k1) {
ep = adjList[k1].nextOut;
while (ep) {
if(adjList[ep->tailv].status || v) os << *ep << endl;
ep = ep->nextOut;
}
adjList[k1].status = 0;
}
os << "the total number of edges in the graph is " << en;
}
Path Graph::dfs1(int index) {
Path p(index < vn ? index : 0, -1, 0);
if (vn < 1) return p;
for (int k1(0); k1 < vn; ++k1) adjList[k1].status = 0;
dfs1(p, p.vStart);
return p;
/* 该方案没有初始化节点状态
Path p(index < vn ? index : 0,-1,0);
if (vn < 1) return p;
EdgeNode *ep(nullptr);
#if PATHEV
p.pathE.push_back(index);
#else
p.pathV.push_back(index);
#endif
adjList[p.vStart].status = 1;
for (ep = adjList[p.vStart].nextOut; ep; ep = ep->nextOut) {
if (adjList[ep->tailv].status) continue;
p += dfs1(ep->tailv);
}
return p;
*/
}
void Graph::dfs1(Path& p, int index) {
EdgeNode *ep(nullptr);
#if PATHEV
p.pathE.push_back(index);
#else
p.pathV.push_back(index);
#endif
adjList[index].status = 1;
for (ep = adjList[index].nextOut; ep; ep = ep->nextOut) {
if (adjList[ep->tailv].status) continue;
p.dist += ep->weight;
dfs1(p, ep->tailv);
}
}
Path Graph::dfs2(int index) {
Path p(index < vn ? index : 0, -1, 0);
if (vn < 1) return p;
for (int k1(0); k1 < vn; ++k1) adjList[k1].status = 0;
stack<int> st;
EdgeNode *ep(nullptr);
int kt(p.vStart);
while (!st.empty() || !adjList[kt].status) {
if (adjList[kt].status) kt = st.top();
else {
st.push(kt);
#if PATHEV
p.pathE.push_back(kt);
#else
p.pathV.push_back(kt);
#endif
adjList[kt].status = 1;
}
for (ep = adjList[kt].nextOut; ep && adjList[ep->tailv].status; ep = ep->nextOut);
if (ep) kt = ep->tailv, p.dist += ep->weight;
else st.pop();
}
return p;
/* 也可以这样实现
Path p(index < vn ? index : 0, -1, 0);
if (vn < 1) return p;
for (int k1(0); k1 < vn; ++k1) adjList[k1].status = 0;
stack<int> st;
EdgeNode *ep(nullptr);
st.push(p.vStart);
#if PATHEV
p.pathE.push_back(p.vStart);
#else
p.pathV.push_back(p.vStart);
#endif
adjList[p.vStart].status = 1;
while (!st.empty()) {
for (ep = adjList[st.top()].nextOut; ep && adjList[ep->tailv].status; ep = ep->nextOut);
if (ep) {
st.push(ep->tailv);
#if PATHEV
p.pathE.push_back(ep->tailv);
#else
p.pathV.push_back(ep->tailv);
#endif
p.dist += ep->weight;
adjList[ep->tailv].status = 1;
}
else st.pop();
}
return p;
*/
}
Path Graph::bfs(int index) {
Path p(index < vn ? index : 0, -1, 0);
if (vn < 1) return p;
queue<int> qt;
EdgeNode *ep(nullptr);
for (int k1(0); k1 < vn; ++k1) adjList[k1].status = 0;
qt.push(p.vStart);
#if PATHEV
p.pathE.push_back(p.vStart);
#else
p.pathV.push_back(p.vStart);
#endif
adjList[p.vStart].status = 1;
while (!qt.empty()) {
for (ep = adjList[qt.front()].nextOut; ep; ep = ep->nextOut) {
if (adjList[ep->tailv].status) continue;
qt.push(ep->tailv);
#if PATHEV
p.pathE.push_back(ep->tailv);
#else
p.pathV.push_back(ep->tailv);
#endif
p.dist += ep->weight;
adjList[ep->tailv].status = 1;
}
qt.pop();
}
return p;
}
Path Graph::mstPrim(int st) {
st = st < vn ? st : 0;
for (int k1(0); k1 < vn; ++k1) adjList[k1].status = 0;
Path pret(st, -1, 0);
adjList[st].status = 1;
vector<Weight> wv(vn, MAXWEIGHT);
vector<int> ev(vn, 0);
for (int k1(1); k1 < vn; ++k1) {
for (auto ep(adjList[st].nextOut); ep; ep = ep->nextOut)
if (!adjList[ep->tailv].status && ep->weight < wv[ep->tailv])
ev[ep->tailv] = ep->eNum, wv[ep->tailv] = ep->weight;
wv[st] = MAXWEIGHT;
for (int k2(0); k2 < vn; ++k2)
if (!adjList[k2].status && wv[k2] < wv[st]) st = k2;
#if PATHEV
pret.pathE.push_back(ev[st]);
#else
pret.pathV.push_back(ev[st]);
#endif
pret.dist += wv[st];
adjList[st].status = 1;
}
return pret;
}
Path Graph::mstKruskal() {
Path pret(-1,-1,0);
vector<EdgeNode*> ev(en);
vector<int> setv(vn);
for (int k1(0); k1 < vn; ++k1) {
for (auto ep = adjList[k1].nextOut; ep; ep = ep->nextOut) ev[ep->eNum] = ep;
}
sort(ev.begin(), ev.end(), [](const EdgeNode* e1, const EdgeNode* e2) {return e1->weight < e2->weight; });
for (int k1(0); k1 < vn; ++k1) setv[k1] =k1;
for (auto ep : ev) {
auto s1(findSet(setv, ep->headv)), s2(findSet(setv, ep->tailv));
if (s1 != s2) {
setv[s1] = s2;
#if PATHEV
pret.pathE.push_back(ep->eNum);
#else
pret.pathV.push_back(ep->eNum);
#endif
pret.dist += ep->weight;
}
}
return pret;
}
vector<Path> Graph::shortestPathBF(int st) {
vector<Path> pret(vn, Path(-1,-1,MAXWEIGHT));
vector<EdgeNode*> ev;
ev.reserve(en << 1);
for (int k1(0); k1 < vn; ++k1) {
for (auto ep = adjList[k1].nextOut; ep; ep = ep->nextOut) ev.push_back(ep);
}
st = st < vn ? st : 0;
pret[st].dist = 0;
for (int k1(1); k1 < vn; ++k1) {
for (size_t k2(0); k2 < ev.size(); ++k2) {
if (pret[ev[k2]->headv].dist != MAXWEIGHT && ev[k2]->weight < pret[ev[k2]->tailv].dist - pret[ev[k2]->headv].dist) {
pret[ev[k2]->tailv].dist = pret[ev[k2]->headv].dist + ev[k2]->weight;
pret[ev[k2]->tailv].vStart = ev[k2]->headv;
pret[ev[k2]->tailv].vEnd = k2;
}
}
}
for (int k1(0), kt(0); k1 < vn; kt = ++k1) {
while (-1 < pret[kt].vStart) {
pret[k1].pathE.push_back(ev[pret[kt].vEnd]->eNum);
kt = pret[kt].vStart;
if (k1 != kt) pret[k1].pathV.push_back(kt);
}
reverse(pret[k1].pathE.begin(), pret[k1].pathE.end());
reverse(pret[k1].pathV.begin(), pret[k1].pathV.end());
}
for (int k1(0); k1 < vn; ++k1) pret[k1].vStart = st, pret[k1].vEnd = k1;
return pret;
}
Path Graph::shortestPathBF(int st, int se) {
st = st < vn ? st : 0;
se = se < vn ? se : 0;
if (st == se) return Path(st, se, 0);
vector<Path> pret(vn, Path(-1, -1, MAXWEIGHT));
vector<EdgeNode*> ev;
ev.reserve(en << 1);
for (int k1(0); k1 < vn; ++k1) {
for (auto ep = adjList[k1].nextOut; ep; ep = ep->nextOut) ev.push_back(ep);
}
pret[st].dist = 0;
for (int k1(1); k1 < vn; ++k1) {
for (size_t k2(0); k2 < ev.size(); ++k2) {
if (pret[ev[k2]->headv].dist != MAXWEIGHT && ev[k2]->weight < pret[ev[k2]->tailv].dist - pret[ev[k2]->headv].dist) {
pret[ev[k2]->tailv].dist = pret[ev[k2]->headv].dist + ev[k2]->weight;
pret[ev[k2]->tailv].vStart = ev[k2]->headv;
pret[ev[k2]->tailv].vEnd = k2;
}
}
}
for (int kt(se); -1 < pret[kt].vStart;) {
pret[se].pathE.push_back(ev[pret[kt].vEnd]->eNum);
kt = pret[kt].vStart;
if (st != kt) pret[se].pathV.push_back(kt);
}
reverse(pret[se].pathE.begin(), pret[se].pathE.end());
reverse(pret[se].pathV.begin(), pret[se].pathV.end());
pret[se].vStart = st, pret[se].vEnd = se;
return pret[se];
}
std::vector<Path> Graph::shortestPathDijkstra(int st) {
vector<Path> pret(vn);
for (int k1(0); k1 < vn; ++k1) {
adjList[k1].status = 0;
pret[k1].dist = MAXWEIGHT;
}
st = st < vn ? st : 0;
pret[st].dist = 0;
adjList[st].status = 1;
for (int k1(1), kt(st); k1 < vn; ++k1) {
for (auto ep(adjList[kt].nextOut); ep; ep = ep->nextOut)
if (!adjList[ep->tailv].status && ep->weight < pret[ep->tailv].dist - pret[kt].dist) {
pret[ep->tailv].dist = pret[kt].dist + ep->weight;
pret[ep->tailv].vStart = kt;
pret[ep->tailv].vEnd = ep->eNum;
}
pret[st].dist = MAXWEIGHT; //先作一变量使用(查找最小顶点时用), 最后再改过来
kt = st;
for (int k2(0); k2 < vn; ++k2)
if (!adjList[k2].status && pret[k2].dist < pret[kt].dist) kt = k2;
#if PATHEV
pret[kt].pathE = pret[pret[kt].vStart].pathE;
pret[kt].pathE.push_back(pret[kt].vEnd);
#else
pret[kt].pathV = pret[pret[kt].vStart].pathV;
if (st != pret[kt].vStart) pret[kt].pathV.push_back(pret[kt].vStart);
#endif
pret[kt].vStart = st;
pret[kt].vEnd = kt;
adjList[kt].status = 1;
}
pret[st].dist = 0;
pret[st].vStart = pret[st].vEnd = st;
return pret;
}
Path Graph::shortestPathDijkstra(int st, int se) {
st = st < vn ? st : 0;
se = se < vn ? se : 0;
if (st == se) return Path(st, se, 0);
vector<Path> pret(vn);
for (int k1(0); k1 < vn; ++k1) {
adjList[k1].status = 0;
pret[k1].dist = MAXWEIGHT;
}
pret[st].dist = 0;
adjList[st].status = 1;
for (int k1(1), kt(st); k1 < vn; ++k1) {
for (auto ep(adjList[kt].nextOut); ep; ep = ep->nextOut)
if (!adjList[ep->tailv].status && ep->weight < pret[ep->tailv].dist - pret[kt].dist) {
pret[ep->tailv].dist = pret[kt].dist + ep->weight;
pret[ep->tailv].vStart = kt;
pret[ep->tailv].vEnd = ep->eNum;
}
pret[kt = st].dist = MAXWEIGHT; //先作一变量使用(查找最小顶点时用), 最后再改过来
for (int k2(0); k2 < vn; ++k2)
if (!adjList[k2].status && pret[k2].dist < pret[kt].dist) kt = k2;
#if PATHEV
pret[kt].pathE = pret[pret[kt].vStart].pathE;
pret[kt].pathE.push_back(pret[kt].vEnd);
#else
pret[kt].pathV = pret[pret[kt].vStart].pathV;
if (st != pret[kt].vStart) pret[kt].pathV.push_back(pret[kt].vStart);
#endif
pret[kt].vStart = st;
pret[kt].vEnd = kt;
if (kt == se) return pret[se];
adjList[kt].status = 1;
}
return Path(st, se, MAXWEIGHT);
}
GraphM::GraphM(istream& is, int n1, int n2, bool v):vn(n1), wMat(n1,vector<Weight>(n1,0)), eMat(n1, vector<Weight>(n1, -1)) {
int v1, v2, e1;
Weight w1;
for (int k1(0); k1 < n2 && is >> e1 >> v1 >> v2 >> w1;) {
if (v1 < vn && v2 < vn && (!wMat[v1][v2] || w1 < wMat[v1][v2])) {
wMat[v1][v2] = w1;
eMat[v1][v2] = e1;
++k1;
if (!v) {
wMat[v2][v1] = w1;
eMat[v2][v1] = e1;
}
}
}
}
bool GraphM::insert(const EdgeNode & e, bool v) {
if (!(e.headv < vn && e.tailv < vn && (!wMat[e.headv][e.tailv] || e.weight < wMat[e.headv][e.tailv]))) return false;
wMat[e.headv][e.tailv] = e.weight;
eMat[e.headv][e.tailv] = e.eNum;
if (!v) {
wMat[e.tailv][e.headv] = e.weight;
eMat[e.tailv][e.headv] = e.eNum;
}
return true;
}
int GraphM::remove(const EdgeNode& e, bool v) {
if (!(e.headv < vn && e.tailv < vn && wMat[e.headv][e.tailv] && wMat[e.headv][e.tailv] == e.weight && eMat[e.headv][e.tailv]==e.eNum)) return 0;
wMat[e.headv][e.tailv] = 0;
eMat[e.headv][e.tailv] = -1;
if (!v) {
wMat[e.tailv][e.headv] = 0;
eMat[e.tailv][e.headv] = -1;
}
return 1;
}
int GraphM::remove(int v1, bool v) {
int ede(0);
for (int k1(0); k1 < vn; ++k1) {
if (k1 == v1) continue;
if (wMat[v1][k1]) {
wMat[v1][k1] = 0;
eMat[v1][k1] = -1;
++ede;
}
if (wMat[k1][v1]) {
wMat[k1][v1] = 0;
eMat[k1][v1] = -1;
++ede;
}
}
ede = v ? ede : ede >> 1;
if (wMat[v1][v1]) {
wMat[v1][v1] = 0;
eMat[v1][v1] = -1;
++ede;
}
return ede;
}
void GraphM::print(bool v, ostream& os) {
int sum(0);
for (int k1(0); k1 < vn; ++k1)
for (int k2(v ? 0 : k1); k2 < vn; ++k2)
if (wMat[k1][k2]) {
os << eMat[k1][k2] << ends << k1 << ends << k2 << ends << wMat[k1][k2] << endl;
++sum;
}
os << "the total number of edges in the graph is " << sum;
}
Path GraphM::dfs1(int st) {
st = st < vn ? st : 0;
Path p(st, -1, 0);
if (vn < 1) return p;
vector<Status> status(vn, 1);
dfs1(p, status, st);
return p;
/* 当status是成员时, 也可以这样实现
st = st < vn ? st : 0;
Path p(st, -1, 0);
if (vn < 1) return p;
#if PATHEV
p.pathE.push_back(st);
#else
p.pathV.push_back(st);
#endif
status[st] = 0;
for (int k1(0); k1 < vn; ++k1) {
if (wMat[st][k1] && status[k1]) p += dfs1(k1);
}
return p;
*/
}
void GraphM::dfs1(Path& p, vector<int>& status, int st) {
#if PATHEV
p.pathE.push_back(st);
#else
p.pathV.push_back(st);
#endif
status[st] = 0;
for (int k1(0); k1 < vn; ++k1) {
if (wMat[st][k1] && status[k1]) {
p.dist += wMat[st][k1];
dfs1(p, status,k1);
}
}
}
Path GraphM::dfs2(int v1) {
v1 = v1 < vn ? v1 : 0;
Path p(v1, -1, 0);
if (vn < 1) return p;
vector<Status> status(vn, 1);
stack<int> st;
int v2;
while (!st.empty() || status[v1]) {
if (status[v1]) {
st.push(v1);
#if PATHEV
p.pathE.push_back(v1);
#else
p.pathV.push_back(v1);
#endif
status[v1] = 0;
}
else v1 = st.top();
for (v2 = 0; v2 < vn && !(wMat[v1][v2] && status[v2]); ++v2);
if (v2 < vn) p.dist += wMat[v1][v2], v1 = v2;
else st.pop();
}
return p;
/* 也可以这样实现
v1 = v1 < vn ? v1 : 0;
Path p(v1, -1, 0);
if (vn < 1) return p;
vector<Status> status(vn, 1);
stack<int> st;
st.push(v1);
#if PATHEV
p.pathE.push_back(v1);
#else
p.pathV.push_back(v1);
#endif
status[v1] = 0;
while (!st.empty()) {
for (v1 = 0; v2 < vn && !(wMat[st.top()][v1] && status[v1]); ++v1);
if (v1 < vn) {
st.push(v1);
p.pathE.push_back(v1);
status[v1] = 0;
}
else st.pop();
}
return p;
*/
}
Path GraphM::bfs(int v1) {
v1 = v1 < vn ? v1 : 0;
Path p(v1, -1, 0);
if (vn < 1) return p;
vector<Status> status(vn, 1);
queue<int> qt;
qt.push(v1);
#if PATHEV
p.pathE.push_back(v1);
#else
p.pathV.push_back(v1);
#endif
status[v1] = 0;
while (!qt.empty()) {
for (int v2(0); v2 < vn; ++v2)
if (wMat[qt.front()][v2] && status[v2]) {
qt.push(v2);
#if PATHEV
p.pathE.push_back(v2);
#else
p.pathV.push_back(v2);
#endif
p.dist += wMat[qt.front()][v2];
status[v2] = 0;
}
qt.pop();
}
return p;
}
Path GraphM::mstPrim(int st) {
st = st < vn ? st : 0;
vector<int> status(vn, 1), ev(vn, 0);
vector<Weight> wv(vn, 0);
Path pret(st, -1, 0);
status[st] = 0;
for (int k1(1); k1 < vn; ++k1) {
for (int k2(0); k2 < vn; ++k2)
if (status[k2] && wMat[st][k2] && (!wv[k2] || wMat[st][k2] < wv[k2])) {
wv[k2] = wMat[st][k2];
ev[k2] = eMat[st][k2];
}
wv[st] = 0;
for (int k2(0); k2 < vn; ++k2)
if (status[k2] && wv[k2] && (!wv[st] || wv[k2] < wv[st])) st = k2;
#if PATHEV
pret.pathE.push_back(ev[st]);
#else
pret.pathV.push_back(ev[st]);
#endif
pret.dist += wv[st];
status[st] = 0;
}
return pret;
}
Path GraphM::mstKruskal() {
Path pret(-1, -1, 0);
vector<int> setv(vn);
vector<EdgeNode> evec;
for (int k1(0); k1 < vn; ++k1) setv[k1] = k1;
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2)
if (wMat[k1][k2]) evec.push_back(EdgeNode(eMat[k1][k2], k1, k2, wMat[k1][k2]));
sort(evec.begin(), evec.end(), [](const EdgeNode e1, const EdgeNode e2) {return e1.weight < e2.weight; });
for (auto e1:evec) {
auto s1(findSet(setv, e1.headv)), s2(findSet(setv, e1.tailv));
if (s1 != s2) {
setv[s1] = s2;
#if PATHEV
pret.pathE.push_back(e1.eNum);
#else
pret.pathV.push_back(e1.eNum);
#endif
pret.dist += e1.weight;
}
}
return pret;
}
vector<Path> GraphM::shortestPathBF(int st) {
st = st < vn ? st : 0;
vector<Path> pret(vn,Path(-1,-1,MAXWEIGHT));
pret[st].dist = 0;
for (int k1(1); k1 < vn; ++k1) {
for (int k2(0); k2 < vn; ++k2)
for (int k3(0); k3 < vn; ++k3)
if (wMat[k2][k3] && pret[k2].dist != MAXWEIGHT && wMat[k2][k3] < pret[k3].dist - pret[k2].dist) {
pret[k3].dist = pret[k2].dist + wMat[k2][k3];
pret[k3].vStart = k2;
//pret[k3].vEnd = eMat[k2][k3];
}
}
for (int k1(0), kt(0); k1 < vn; kt = ++k1) {
while (-1 < pret[kt].vStart) {
//pret[k1].pathE.push_back(pret[kt].vEnd);
pret[k1].pathE.push_back(eMat[pret[kt].vStart][kt]);
kt = pret[kt].vStart;
if(k1!=kt) pret[k1].pathV.push_back(kt);
}
reverse(pret[k1].pathE.begin(), pret[k1].pathE.end());
reverse(pret[k1].pathV.begin(), pret[k1].pathV.end());
}
for (int k1(0); k1 < vn; ++k1) pret[k1].vStart = st, pret[k1].vEnd = k1;
return pret;
}
Path GraphM::shortestPathBF(int st, int se) {
st = st < vn ? st : 0;
se = se < vn ? se : 0;
if (st == se) return Path(st, se, 0);
vector<Path> pret(vn, Path(-1, -1, MAXWEIGHT));
pret[st].dist = 0;
for (int k1(1); k1 < vn; ++k1) {
for (int k2(0); k2 < vn; ++k2)
for (int k3(0); k3 < vn; ++k3)
if (wMat[k2][k3] && pret[k2].dist != MAXWEIGHT && wMat[k2][k3] < pret[k3].dist - pret[k2].dist) {
pret[k3].dist = pret[k2].dist + wMat[k2][k3];
pret[k3].vStart = k2;
//pret[k3].vEnd = eMat[k2][k3];
}
}
for (int kt(se); -1 < pret[kt].vStart;) {
pret[se].pathE.push_back(eMat[pret[kt].vStart][kt]);
kt = pret[kt].vStart;
if(st!=kt) pret[se].pathV.push_back(kt);
}
reverse(pret[se].pathE.begin(), pret[se].pathE.end());
reverse(pret[se].pathV.begin(), pret[se].pathV.end());
pret[se].vStart = st, pret[se].vEnd = se;
return pret[se];
}
std::vector<Path> GraphM::shortestPathDijkstra(int st) {
vector<Path> pret(vn,Path(1,0,MAXWEIGHT));
st = st < vn ? st : 0;
pret[st].dist = 0;
pret[st].vStart = 0; // 记录节点状态
for (int k1(1), kt(st); k1 < vn; ++k1) {
for (int k2(0); k2 < vn; ++k2)
if (wMat[kt][k2] && pret[k2].vStart && wMat[kt][k2] < pret[k2].dist - pret[kt].dist) {
pret[k2].dist = pret[kt].dist + wMat[kt][k2];
pret[k2].vEnd = kt; // 存储前驱节点
}
pret[kt = st].dist = MAXWEIGHT; //先作一变量使用(查找最小顶点时用), 最后再改过来
for (int k2(0); k2 < vn; ++k2)
if (pret[k2].vStart && pret[k2].dist < pret[kt].dist) kt = k2;
#if PATHEV
pret[kt].pathE = pret[pret[kt].vEnd].pathE;
pret[kt].pathE.push_back(eMat[pret[kt].vEnd][kt]);
#else
pret[kt].pathV = pret[pret[kt].vEnd].pathV;
if (st != pret[kt].vEnd) pret[kt].pathV.push_back(pret[kt].vEnd);
#endif
pret[kt].vStart = 0;
}
pret[st].dist = 0;
for (int k1(0); k1 < vn; ++k1) pret[k1].vStart = st, pret[k1].vEnd = k1;
return pret;
}
Path GraphM::shortestPathDijkstra(int st, int se) {
st = st < vn ? st : 0;
se = se < vn ? se : 0;
if (st == se) return Path(st, se, 0);
vector<Path> pret(vn, Path(1, 0, MAXWEIGHT));
pret[st].dist = 0;
pret[st].vStart = 0; // 记录节点状态
for (int k1(1), kt(st); k1 < vn; ++k1) {
for (int k2(0); k2 < vn; ++k2)
if (wMat[kt][k2] && pret[k2].vStart && wMat[kt][k2] < pret[k2].dist - pret[kt].dist) {
pret[k2].dist = pret[kt].dist + wMat[kt][k2];
pret[k2].vEnd = kt; // 存储前驱节点
}
pret[kt = st].dist = MAXWEIGHT; //先作一变量使用(查找最小顶点时用), 最后再改过来
for (int k2(0); k2 < vn; ++k2)
if (pret[k2].vStart && pret[k2].dist < pret[kt].dist) kt = k2;
#if PATHEV
pret[kt].pathE = pret[pret[kt].vEnd].pathE;
pret[kt].pathE.push_back(eMat[pret[kt].vEnd][kt]);
#else
pret[kt].pathV = pret[pret[kt].vEnd].pathV;
if (st != pret[kt].vEnd) pret[kt].pathV.push_back(pret[kt].vEnd);
#endif
if (kt == se) {
pret[se].vStart = st;
pret[se].vEnd = se;
return pret[se];
}
pret[kt].vStart = 0;
}
return Path(st,se,MAXWEIGHT);
}
vector<vector<Path>> GraphM::shortestPathFloyd() const {
#if PATHEV
auto w(wMat);
vector<vector<int>> v(vn, vector<int>(vn));
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2)
v[k1][k2] = k1;
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2)
for (int k3(0); k3 < vn; ++k3)
if (w[k2][k1] && w[k1][k3] && (!w[k2][k3] || w[k2][k1] + w[k1][k3] < w[k2][k3])) {
w[k2][k3] = w[k2][k1] + w[k1][k3];
v[k2][k3] = v[k1][k3];
}
vector<vector<Path>> pret(vn, vector<Path>(vn));
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2) {
pret[k1][k2].vStart = k1;
pret[k1][k2].vEnd = k2;
if (!w[k1][k2]) pret[k1][k2].dist = MAXWEIGHT;
else {
pret[k1][k2].dist = w[k1][k2];
for (int k3(k2); k1 != k3; k3 = v[k1][k3]) pret[k1][k2].pathE.push_back(eMat[v[k1][k3]][k3]);
reverse(pret[k1][k2].pathE.begin(), pret[k1][k2].pathE.end());
}
}
return pret;
#else
auto w(wMat);
vector<vector<int>> v(vn, vector<int>(vn, -1));
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2)
for (int k3(0); k3 < vn; ++k3)
if (w[k2][k1] && w[k1][k3] && (!w[k2][k3] || w[k2][k1] + w[k1][k3] < w[k2][k3])) {
w[k2][k3] = w[k2][k1] + w[k1][k3];
v[k2][k3] = k1;
}
vector<vector<Path>> pret(vn, vector<Path>(vn));
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2) {
pret[k1][k2].vStart = k1;
pret[k1][k2].vEnd = k2;
if (!w[k1][k2]) pret[k1][k2].dist = MAXWEIGHT;
else {
pret[k1][k2].dist = w[k1][k2];
vPass(pret[k1][k2], v, k1, k2);
}
}
return pret;
#endif
}
Path GraphM::shortestPathFloyd(int st, int se) const {
st = st < vn ? st : 0;
se = se < vn ? se : 0;
if (st == se) return Path(st, se, 0);
#if PATHEV
auto w(wMat);
vector<vector<int>> v(vn, vector<int>(vn));
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2)
v[k1][k2] = k1;
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2)
for (int k3(0); k3 < vn; ++k3)
if (w[k2][k1] && w[k1][k3] && (!w[k2][k3] || w[k2][k1] + w[k1][k3] < w[k2][k3])) {
w[k2][k3] = w[k2][k1] + w[k1][k3];
v[k2][k3] = v[k1][k3];
}
if (!w[st][se]) return Path(st, se, MAXWEIGHT);
Path pret(st, se, w[st][se]);
for (; st != se; se = v[st][se]) pret.pathE.push_back(eMat[v[st][se]][se]);
reverse(pret.pathE.begin(), pret.pathE.end());
return pret;
#else
auto w(wMat);
vector<vector<int>> v(vn, vector<int>(vn, -1));
for (int k1(0); k1 < vn; ++k1)
for (int k2(0); k2 < vn; ++k2)
for (int k3(0); k3 < vn; ++k3)
if (w[k2][k1] && w[k1][k3] && (!w[k2][k3] || w[k2][k1] + w[k1][k3] < w[k2][k3])) {
w[k2][k3] = w[k2][k1] + w[k1][k3];
v[k2][k3] = k1;
}
if (!w[st][se]) return Path(st, se, MAXWEIGHT);
Path pret(st, se, w[st][se]);
vPass(pret, v, st, se);
return pret;
#endif
}