基于邻接链表和邻接矩阵实现图的各种常用函数C++ ...

基于图的邻接链表和邻接矩阵实现图的各种常用函数

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







转载于:https://www.cnblogs.com/lmjy/p/7183896.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值