并查集和图的基本

本文介绍了并查集的基本概念、规则和实现,以及图的分类(有向图、无向图和完全图),重点讲解了邻接矩阵在表示图中的优缺点。通过实例说明,展示了图在解决实际问题中的重要性。
摘要由CSDN通过智能技术生成

🫥并查集和图的基本

✨啦啦啦,我又来了,今天的内容是数据结构——并查集和图,相信大家在数据结构的学习中不止一次的听说过这两员大将,而且或多或少的都受到过他的拷打。今天作者以身入局,试试它的深浅🐻
ac70292b9bb5f86382b4547809a00f3.jpg


本文由爱吃苹果的清梦友情提供,本图出自可爱的婷婷
🐨如果文章对您有用的话,请给一个三连,您的支持对我十分重要

前言

基于前边的基础数据结构还是无法完全应对全部需求,例如:
当我们面对路线规划问题的时候,如何得到最优规划方案?
面对关系网络的时候,我如何划分关系的远近……
image.png
又或者是我们在面对这个图的时候,我们如何把图转换成抽象的结构储存起来?
面对这一系列的问题,我们需要引进一些高级的数据结构来进行处理这些状态,来解决这些问题。

并查集

在了解之前,我们需要对并查集 进行了解实现,因为图的后边需要用到这个数据结构实现功能。
那么在了解并查集的时候,我们要引入一个情景,假设,你现在在A公司进行暑期实习,和你一块实习的有很多小伙伴。可是,你觉得自己一个人没有认识的人很是孤单,所以你决定通过名单信息找一下自己的同乡,顺便把同事属于哪个地方分类统计。
那么,你可以选择,一个一个的看,但是在记录的时候,你总归会把他们相同的划分在同一个城市的一个集合中。
所以我们如果把这个过程抽象一下就是:
image.png
我们可以将这几个省份分别划分成a ,b ,c ,d ,几个集合,然后划分过程我们可以看作从一堆东西中挑出来放进对应的集合,过程可以模拟成下面的情况:
image.png
那么我们把他们放在集合中,得到名单的过程可以看作将同一个特征的的同学链接串联起来
image.png
但是这样的结构,访问起来会有一定的时间消耗,会影响数据结构的时间效率,所以我们要对这种结构进行优化,而并查集,为我们提供了另外一种思路:
image.png
那就是将同特征的变成树形结构进行存放,但是是以多叉树的情况进行存储的,这样,能够直接把集合的连接点凸显出来,也就是不同两个个体的关系重合部分展现出来,便于和其他集合的链接。
它的基本思想就是把每个数据都看作一个集合,然后,如果有相同的特征,就把集合进行链接,只不过要确定一个中心点,便于后续的链接。
image.png

可以看得到的是,我们一开始是将每个元素都看成集合的开头,也就是自身就是一个集合,然后将同样特征的连接起来,成为新的集合。
同时,并查集提供的方法并不是让你直接使用树结构进行存储,而是类似于堆的实现采用静态数组进行实现,而且存的并不是孩子节点,而是双亲节点的位置,每个孩子都是指向根的这样方便后续集合建立连接进行操作,因为并查集其实重视的集合的关系,并不是主要用父子关系对其进行简单的概括。
所以我们只要有一个集合的入口根节点就可以,其实这就相当于是一个麻袋。
image.png
那个根节点相当于是麻袋的口,而且从另一个角度来讲,它更像是一个链接节点,用来链接其他的集合进行合并。

基本规则

对于并查集的思想有一定的了解之后我们就要跟学习其他数据结构一样了解一下它的具体规则和相应构成:

  1. 从一般设计上来讲我们通常习惯于,用一个数组来反映这样的树状结构这样不会产生访问困难的问题,然后确定用来表示情况的几种数据:
    image.png

  2. 至于节点的关于数组的映射来说,我们要借助vector,map进行实现,,这样可以事项,对于数据的双向访问。

  3. 因为map实现对应的key转换成数组对应的下标,用来对于集合进行访问,而且用vector存储所有输入的key,那么又能实现了下标访问对应的key。实现了双向的映射
    image.png

数据结构的实现

了解了这么多我们终于还是来到了,实战,老话说 光说不练那是假把式,又说又练那是真把式
下面是我实现的一种思路代码:

template<class K>
class ufs
{
	//用来映射存储数据,和集合
	//存储森林
	//森林的值不一定是整形
	vector<int> arr;
	//用来映射对应的元素
	map<K, int> order_map;
	vector<K> get;
public:
	template<class InputIterator>
	ufs(InputIterator begin, InputIterator end)
	{
		//定义一共多少数据
		auto it = begin;
		int key = 0;
		while (it != end)
		{
			arr.push_back(-1);
			get.push_back(*it);
			order_map[*it] = key++;

			it++;
		}
	}
	//找到根节点
	K find_root(K tem)
	{
		//就是根据数组进行遍历
		if (!order_map.count(tem))
		{
			return K();
		}
		int or1 = order_map[tem];
		while (arr[or1] >= 0)
		{
			or1 = arr[or1];
		}
		return get[or1];
	}
	//

	bool link(K tem1, K tem2)
	{
		if (!order_map.count(tem1) || tem1 == tem2)
		{
			return false;
		}
		int k1 = order_map[find_root(tem1)];
		int k2 = order_map[find_root(tem2)];
		int root = max(k1, k2);
		int opt = min(k1, k2);
		arr[root] += arr[opt];

		arr[opt] = root;
		return true;
	}
	size_t amount()
	{
		size_t cnt = 0;
		for (auto i : arr)
			if (i < 0)
				cnt++;
		return cnt;
	}
	int get_num(K tem)
	{

		return	abs(arr[order_map[find_root(tem)]]);
	}
	~ufs()
	{}
};

有了并查集的基础让我们进入到图的学习吧!!

加油少年
## 图及其相关基础 所谓的图,我们要从一个具体的例子入手,当我们走迷宫的时候收到一份由点和线链接组成的一个 `闭合` 亦或者是 `不闭合的图形`。 那个其实就是我们说的图。 ![image.png](https://img-blog.csdnimg.cn/img_convert/2ff009391565071b3f35dce91d93daba.png) 从上边的图我们可以得到,图的基本特征: >1. 包括各个地点,和链接各个节点的对应路径 >2. 我们可以类比我们小时候闲来无事画的地图之类的,我们又可以发现这个线段可以包含以下特征: > (1) 路径长度 > (2)路径方向 > (3) 是否存在 > (4) 两端的节点

所以我们就能根据这些对于相应的特征进行一定的分类:

分类

有向图和无向图

根据边是否存在方向及进行分类,看是否有指向方向

有向图两个节点之间路径可能会存在差异,但是无向图则是对应的点路径都是对称的

image.png

完全图

当一个图中存在n个节点,有n * (n - 1) / 2条边,且每两个节点之间有且只有一条边,那么则称这个图为 无向完全图

image.png
若存在 n * (n - 1) 条边的话,而且两个节点之间有且只有两条方向相反的边,则称这个图则是有向完全图

当然对于图还有好多概念,但是现在一股脑的抛出来,不利于解释,让我们细水长流嘿嘿

数据结构具体实现结构简析

但是如此复杂的结构,我们要用什么样的结构类进行封装才能实现呢??这是一个问题。
那让我们翻翻书,看看有什么思路……
Lucky,果然让我们找到了
image.png
可以看到的是,图其实就是边和顶点的集合,那么我们只要将路径表现出来,或者是将路径战术出来就可以了,所以图的数据结构给我们提供了两种思路 邻接矩阵邻接表
image.png

邻接矩阵

这个结构其实比较巧的设计就是用二维数组的下标来表示,横坐标对应得点通向纵坐标的权值,又或者是是否通过取去

下面我们就对图转换为邻接矩阵的过程,进行演示:
image.png

这种方式的优缺点

对于路径的取用可以达到O(1) 水平了,但是没有办法知道一个节点向各个路径的路线,所以对于图的节点太少的话,空间上反倒是划不来。

邻接矩阵

这种表示方法是根据一个节点出发的路径,来进行诠释的

image.png

这种方式的优缺点

这种方式可以得到具体的路径表示,但是对于一些顶点较多的图,路径较多的图无法进行表示。时间复杂度和空间复杂度达不到。

略微的总结

图是一种非线性的数据结构,用于表示元素之间的关系。它由节点(也称为顶点)和连接节点的边组成。每个节点可以与其他节点直接或间接连接,这些连接关系可以具有方向性(有向图)或无方向性(无向图)。因此,图可用于表示各种关系,如网络、社交关系、地图等,并且在计算机科学和现实生活中有广泛的应用。

后记

对于图我们还有很长的路来进行走的,对于实现和接口的设计,我们也要继续努力。让我们以我超级喜欢的人说的一句话浅浅的来个结尾吧:
2a798261dc3b6254e16104e04602976.jpg

万物可爱,生活明朗
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值