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

本文介绍了如何使用C++基于邻接链表和邻接矩阵来实现图的各种基本操作,包括图的创建、销毁、边的增删、深度优先和广度优先遍历、最小生成树以及最短路径算法。提供了具体的代码实现,并展示了运行结果。
摘要由CSDN通过智能技术生成

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值