【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS)

这篇具有很好参考价值的文章主要介绍了【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V, E),其中:
顶点集合V = {x|x属于某个数据对象集}是有穷非空集合;
E = {(x,y)|x,y属于V}或者E = {<x, y>|x,y属于V && Path(x, y)}是顶点间关系的有穷集合,也叫
做边的集合。
完全图:在有n个顶点的无向图中,若有n * (n-1)/2条边,即任意两个顶点之间有且仅有一条边,
则称此图为无向完全图,比如上图G1;在n个顶点的有向图中,若有n * (n-1)条边,即任意两个
顶点之间有且仅有方向相反的边,则称此图为有向完全图

1.图的存储结构

因为图中既有节点,又有边(节点与节点之间的关系),因此,在图的存储中,只需要保存:节点和
边关系即可。
节点保存比较简单,只需要一段连续空间即可,那边关系该怎么保存呢?

1.邻接矩阵

因为节点与节点之间的关系就是连通与否,即为0或者1,因此邻接矩阵(二维数组)即是:先用一
个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系。

【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS),数据结构,宽度优先,深度优先

2.邻接表

【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS),数据结构,宽度优先,深度优先

一、邻接矩阵

主要思想就是,先建立顶点与数组下标的映射关系,我们通过这个两个顶点对应的下标,确定其在二维数组(邻接矩阵)中的位置,然后将邻接矩阵对应位置修改为权值(找顶点与下标关系之所以还要一个函数来控制而不用哈希表是因为我们要找的顶点可能不存在,如果用哈希表就会直接将这个不存在的顶点插入进去)

namespace matrix {
	//V为顶点类型,W为边权值类型,MAX_W为权值最大值也就是无效值
	//Direction用来判断是不是有向图,false为无向图
	template<class V, class W, W  MAX_W = INT_MAX, bool Direction = false>
	class Graph {
	public:

		Graph(const V* a, size_t n) {
			_vertexs.reserve(n);
			for (size_t i = 0; i < n; i++) {
				_vertexs.push_back(a[i]);
				_indexMap[a[i]] = i;
				//将顶点存入_vertexs,下标映射存进map
			}

			_matrix.resize(n);
			for (size_t i = 0; i < _matrix.size(); i++) {
				_matrix[i].resize(n, MAX_W);
				//邻接矩阵默认初始值为无效值
			}
		}

		size_t GetVertexIndex(const V& v) {
			//获得对应顶点在数组中的下标
			auto it = _indexMap.find(v);
			if (it != _indexMap.end()) {
				return it->second;
				//有这个顶点返回其下标
			}
			else {
				throw("顶点不存在");
				return -1;
			}
		}

		void _AddEdge(size_t srci, size_t dsti, const W& w) {
			//存入权值
			_matrix[srci][dsti] = w;
			if (Direction == false) {
				_matrix[dsti][srci] = w;
				//无向图要两个方向都存
			}
		}

		void AddEdge(const V& src, const V& dst, const W& w) {
			//添加边与顶点的关系。从src到dst方向的关系
			size_t srci = GetVertexIndex(src);
			size_t dsti = GetVertexIndex(dst);
			//先获取其对应的下标
			_AddEdge(srci, dsti, w);
		}

		void Print() {
			for (size_t i = 0; i < _vertexs.size(); i++) {
				cout << "[" << i << "]" << "->" << _vertexs[i] << endl;
			}//打印顶点集
			cout << endl;


			//打印邻接矩阵
			for (size_t i = 0; i < _matrix.size(); i++) {
				cout << i << " ";
				for (size_t j = 0; j < _matrix[i].size(); j++) {
					if (_matrix[i][j] == MAX_W) {
						printf("%4c", '*');
					}
					else {
						printf("%4d", _matrix[i][j]);
					}
				}
				cout << endl;
			}
		}
	 

	private:
		vector<V>_vertexs;//顶点集合
		map<V, int>_indexMap;//存顶点与数组下标的映射关系
		vector<vector<W>>_matrix;//邻接矩阵
	};



}

用邻接矩阵存储图的有点是能够快速知道两个顶点是否连通,缺陷是如果顶点比较多,边比
较少时,矩阵中存储了大量的0成为系数矩阵,比较浪费空间,并且要求两个节点之间的路
径不是很好求。

二、邻接表

namespace link_table {
	template<class W>
	struct Edge {//Edge用来保存边的关系,当作结点来使
		int _dsti;//目标顶点对应下标
		W _w;//权值
		Edge<W>* _next;

		Edge(int dsti, const W& w)
			:_dsti(dsti),
			_w(w),
			_next(nullptr)
		{}


	};
	template<class V, class W, bool Direction = false>

	class Graph {
		typedef Edge<W> Edge;//注意这里typedf要传参
	public:
		Graph(const V* a, size_t n) {
			_vertexs.reserve(n);
			for (int i = 0; i < n; i++) {
				_vertexs.push_back(a[i]);
				_indexMap[a[i]] = i;
				//将顶点放入数组,并建立顶点与下标的映射关系
			}
			_tables.resize(n, nullptr);
		}

		size_t GetVertexIndex(const V& v) {
			//查找顶点对应的下标,这里不直接用哈希表
			//来查是因为顶点可能不存在
			auto it = _indexMap.find(v);
			if (it != _indexMap.end()) {
				return it->second;
			}
			else {
				throw ("顶点不存在");
				return -1;
			}
		}

		void AddEdge(const V& src, const V& dst, const W& w) {
			size_t srci = GetVertexIndex(src);
			size_t dsti = GetVertexIndex(dst);

			Edge* eg = new Edge(dsti, w);
			eg->_next = _tables[srci];
			_tables[srci] = eg;
			if (Direction == false) {//如果为无向图,两个顶点都要加权值记录
				Edge* eg = new Edge(srci, w);
				eg->_next = _tables[dsti];
				_tables[dsti] = eg;
			}
		}

		void Print() {
			for (size_t i = 0; i < _vertexs.size(); i++) {
				cout << "[" << i << "]" << _vertexs[i] << endl;
			}//打印顶点集合
			cout << endl;

			//打印邻接表
			for (size_t i = 0; i < _tables.size(); i++) {
				cout << _vertexs[i] << "[" << i << "]->";
				Edge* cur = _tables[i];
				while (cur) {
					cout << "[" << _vertexs[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << endl;
					cur = cur->_next;
				}
				cout << "nullptr" << endl;
			}
		}


	private:
		vector<V>_vertexs;//顶点数组
		vector<Edge*>_tables;//邻接表
		map<V, int> _indexMap;//顶点与下标的映射关系
	};

}

二、图的遍历

1.DFS

【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS),数据结构,宽度优先,深度优先

	void _DFS(size_t srci, vector<bool>& visited) {
			cout << srci << ":" << _vertexs[srci] << endl;
			visited[srci] = true;//标记这个顶点被访问过了
			for (size_t i = 0; i < _vertexs.size(); i++) {
				if (_matrix[srci][i] != MAX_W && visited[i] == false) {
					_DFS(i, visited);
				}
			}
		}

		void DFS(const V& src) {
			size_t srci = GetVertexIndex(src);
			vector<bool>visited(_vertexs.size(), false);

			_DFS(srci, visited);
		}

2.BFS

【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS),数据结构,宽度优先,深度优先文章来源地址https://www.toymoban.com/news/detail-764244.html

void BFS(const V& src) {
			size_t srci = GetVertexIndex(src);
			queue<int>q;
			q.push(srci);
			vector<bool>visited(_vertexs.size(), false);
			visited[srci] = true;//标记这个顶点被访问过了
			int levelSize = 1;
			while (!q.empty()) {
				//levelSize为当前层的大小
				for (size_t i = 0; i < levelSize; i++) {
					int front = q.front();
					q.pop();
					cout << front << ":" << _vertexs[front]<<" ";

					for (size_t i = 0; i < _vertexs.size(); i++) {
						if (_matrix[front][i] != MAX_W && visited[i] == false) {
							q.push(i);
							visited[i] = true;//标记这个顶点被访问过了
						}
					}
				}
				levelSize = q.size();//更新当前层的数量
				cout << endl;
			}
			cout << endl;
		}

到了这里,关于【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 24考研数据结构-图的存储结构邻接矩阵

    【1】顶点的结点结构 ——————— | data | firstarc | ——————— data数据域:储存顶点vi firstarc链域:指向链表中第一个结点 【2】弧的结点结构 —————————— | adjvex | info | nextarc | —————————— adjvex邻接点域:与顶点vi邻接的点在图中的位置 info数据域

    2024年02月14日
    浏览(54)
  • C++数据结构之图的存储结构——邻接矩阵和邻接表实现无向图

    关键点: 1.构建二维数组 2.对应边的位置赋值为1 由于比较简单就直接上代码: 个人对邻接表实现无向图的理解如下,仅供参考:         由于无向图的组成是由多个顶点和多条无向边组成的,因此我们可以把它拆分成两个结构,分别是顶点和无向边,又由于我们是使用

    2024年02月05日
    浏览(49)
  • 【数据结构与算法】图的基本概念 | 邻接矩阵和邻接表 | 广度优先遍历和深度优先遍历

    🌠 作者:@ 阿亮joy. 🎆 专栏:《数据结构与算法要啸着学》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V, E) ,其中: 顶点集合V = {x|x属于某

    2024年02月04日
    浏览(69)
  • 数据结构实验6 :图的存储与遍历(邻接矩阵的深度优先遍历DFS和邻接表的广度优先遍历BFS)

    利用邻接矩阵存储无向图,并从0号顶点开始进行深度优先遍历。 输入第一行是两个整数n1 n2,其中n1表示顶点数(则顶点编号为0至n1-1),n2表示图中的边数。 之后有n2行输入,每行输入表示一条边,格式是“顶点1 顶点2”,把边插入图中。 例如: 4 4 0 1 1 3 0 3 0 2 先输出存储

    2024年02月09日
    浏览(63)
  • 数据结构-邻接矩阵的创建与遍历

    上篇文章已经介绍了邻接矩阵的具体作用与如果利用邻接矩阵寻找相邻顶点,这次介绍重点为邻接矩阵的创建与两种遍历方式 邻接矩阵的创建 其结构体需要能记录顶点、顶点数、边数及邻接矩阵,即 创建方式则为读入边数、顶点数即各边的两个顶点和权值 图的遍历 DFS(深

    2024年02月20日
    浏览(44)
  • 数据结构几种常见图的邻接矩阵的画法(有向图带权值,有向图不带权值,无向图带权值,无向图不带权值)

    这不马上要期末考试了,复习的时候突然发现了有好几种图的邻接矩阵需要画,在网上找了半天结果发现也没有特别详细的总结,所以经过总结写一下吧,希望对有需要的人,有点帮助吧!!!!(如有不对还请见谅!!!!!~~~~~~) 1,有向图带权值   2.有向图不带权值

    2024年02月13日
    浏览(50)
  • 数据结构--图的存储邻接表法

    邻接矩阵: 数组实现的顺序存储,空间复杂度高,不适合存储稀疏图 邻接表: 顺序+链式存储 无向图: 边结点的数量是 2|E|, 整体空间复杂度为 O(|V| + 2|E|) 有向图: 边结点的数量是 |E|, 整体空间复杂度为 O(|V| + |E|) 图的邻接表表示方式并不唯一 color{red}图的邻接表表示方

    2024年02月16日
    浏览(44)
  • 数据结构-图的邻接表的定义与实现

    目录 一、引言 二、图的基本概念 三、图的存储方式 1. 邻接矩阵 2. 邻接表 3. 十字链表 4. 邻接多重表 四、邻接表的实现 1. 邻接表的定义 2. 邻接表的构建 3. 邻接表的遍历 五、邻接表的优缺点 六、总结 在计算机科学中,图是一种非常重要的数据结构,它是由节点和边组成的

    2024年02月03日
    浏览(39)
  • 数据结构--5.1图的存储结构(十字链表、邻接多重表、边集数组)

    目录 一、十字链表(Orthogonal List) 二、邻接多重表 三、边集数组 四、深度优先遍历   重新定义顶点表结点结构:  data firstIn firstOut 重新定义边表结构结点: tailVex headVex headLink tailLink        十字链表的好处就是因为把邻接表和逆邻接表整合在了一起,这样既容易找到Vi为

    2024年02月10日
    浏览(42)
  • 图的创建(详解邻接矩阵和邻接表)

    首先,我们来看一下涉及的知识点: 图 :图 G=(V,E) 由 顶点 集 V 和 边 集 E 组成。每条边对应一个点对 (v,w),其中 v,w 属于 V 。如果图中的点对是有序的,那么该图就是 有向图 ,反之为 无向图 。 邻接点 :若顶点 v 与 w 之间存在一条边,则认为顶点 v 与 w 邻接。 权 :图中

    2024年02月06日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包