基于邻接链表和邻接矩阵实现图的各种常用函数C++ 标签: 图邻接链表邻接矩阵最短路径遍历和最小生成树 2017-06-01 19:33 56人阅读
基于图的邻接链表和邻接矩阵实现图的各种常用函数
图最常用的表示方法有邻接链表和邻接矩阵;图的常见函数包括图的建立和销毁,边的插入删除,图的深度优先和广度优先遍历,最小生成树,最短路径等。下面代码在邻接链表和邻接矩阵的基础上分别实现了函数,其中类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 }
lmjy