高阶数据结构--图(graph)

图(graph)

  • 1.并查集
    • 1. 并查集原理
    • 2. 并查集实现
    • 3. 并查集应用
  • 2.图的基本概念
  • 3. 图的存储结构
    • 3.1 邻接矩阵
    • 3.2 邻接矩阵的代码实现
    • 3.3 邻接表
    • 3.4 邻接表的代码实现
  • 4. 图的遍历
    • 4.1 图的广度优先遍历
    • 4.2 广度优先遍历的代码

1.并查集

1. 并查集原理

在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这类问题的抽象数据类型称为并查集(union-find
set)。

比如:某公司今年校招全国总共招生10人,西安招4人,成都招3人,武汉招3人,10个人来自不
同的学校,起先互不相识,每个学生都是一个独立的小团体,现给这些学生进行编号:{0, 1, 2, 3,4, 5, 6, 7, 8, 9}; 给以下数组用来存储该小集体,数组中的数字代表:该小集体中具有成员的个
数。(负号下文解释)
在这里插入图片描述
毕业后,学生们要去公司上班,每个地方的学生自发组织成小分队一起上路,于是:

西安学生小分队s1={0,6,7,8},成都学生小分队s2={1,4,9},武汉学生小分队s3={2,3,5}就相互认识了,10个人形成了三个小团体。假设右三个群主0,1,2担任队长,负责大家的出行。
在这里插入图片描述
一趟火车之旅后,每个小分队成员就互相熟悉,称为了一个朋友圈。
在这里插入图片描述
从上图可以看出:编号6,7,8同学属于0号小分队,该小分队中有4人(包含队长0);编号为4和9的同学属于1号小分队,该小分队有3人(包含队长1),编号为3和5的同学属于2号小分队,该小分队有3个人(包含队长1)。
仔细观察数组中内融化,可以得出以下结论:

  1. 数组的下标对应集合中元素的编号
  2. 数组中如果为负数,负号代表根,数字代表该集合中元素个数
  3. 数组中如果为非负数,代表该元素双亲在数组中的下标

在公司工作一段时间后,西安小分队中8号同学与成都小分队1号同学奇迹般的走到了一起,两个
小圈子的学生相互介绍,最后成为了一个小圈子:

在这里插入图片描述
现在0集合有7个人,2集合有3个人,总共两个朋友圈。
通过以上例子可知,并查集一般可以解决一下问题:

  1. 查找元素属于哪个集合
    沿着数组表示树形关系以上一直找到根(即:树中中元素为负数的位置)
  2. 查看两个元素是否属于同一个集合
    沿着数组表示的树形关系往上一直找到树的根,如果根相同表明在同一个集合,否则不在
  3. 将两个集合归并成一个集合
    -将两个集合中的元素合并
    -将一个集合名称改成另一个集合的名称
  4. 集合的个数
    遍历数组,数组中元素为负数的个数即为集合的个数。

2. 并查集实现

template<class T>
class UnionFindSet
{
public:
	UnionFindSet(size_t n):
	_ufs(n,-1)
	{}

	int Find(int x)//查找根
	{
		int root = x;
		while (_ufs[root] >= 0)
		{
			root = _ufs[root];
		}

		return root;
	}

	void Union(int x1, int x2)
	{
		int x = Find(x1);
		int y = Find(x2);

		if (x == y)
			return;//本来就在一个团体

		_ufs[x] += _ufs[y];
		_ufs[y] = x;
	}

	bool Inset(int x1, int x2)
	{
		return Find(x1) == Find(x2);
	}

	size_t SetSize()
	{
		size_t size = 0;
		for (size_t i = 0; i < _ufs.size(); i++)
		{
			if (_ufs[i] < 0)
				size++;
		}

		return size;
	}

private:
	vector<T> _ufs;
};

此外为了学习图这个非常难得数据结构我这里补充一下通过编号找名字,通过名字找编号如何实现:

//template<class T>
//class UnionFindSet
//{
//public:
//
//	UnionFindSet(const T* a, const size_t n)
//	{
//		for (size_t i = 0; i < n; i++)
//		{
//			_a.push_back(a[i]);
//			_indexMap[a[i]] = i;
//		}
//	}
//
//private:
//	vector<T> _a;//编号找名字
//	map<T, int> _indexMap;//名字找编号
//};

实现后的效果如图:
在这里插入图片描述
将以上内容理解清楚我们才能进入更好地进入图的学习。

3. 并查集应用

https://leetcode.cn/problems/bLyHh0/

https://leetcode-cn.com/problems/satisfiability-of-equality-equations/comments/

以上两个题就是并查集能解决的问题,由于我们主要的目标是学习图,所以需要答案可以私信我

2.图的基本概念

图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V, E),其中:
顶点集合V = {x|x属于某个数据对象集}是有穷非空集合;

E = {(x,y)|x,y属于V}或者E = {<x, y>|x,y属于V && Path(x, y)}是顶点间关系的有穷集合,也叫
做边的集合。

(x, y)表示x到y的一条双向通路,即(x, y)是无方向的;Path(x, y)表示从x到y的一条单向通路,即
Path(x, y)是有方向的。

顶点和边:图中结点称为顶点,第i个顶点记作vi。两个顶点vi和vj相关联称作顶点vi和顶点vj之间
有一条边,图中的第k条边记作ek,ek = (vi,vj)或<vi,vj>。

有向图和无向图:在有向图中,顶点对<x, y>是有序的,顶点对<x,y>称为顶点x到顶点y的一条
边(弧),<x, y>和<y, x>是两条不同的边,比如下图G3和G4为有向图。在无向图中,顶点对(x, y)
是无序的,顶点对(x,y)称为顶点x和顶点y相关联的一条边,这条边没有特定方向,(x, y)和(y,x)
是同一条边,比如下图G1和G2为无向图。注意:无向边(x, y)等于有向边<x, y>和<y, x>。

在这里插入图片描述
完全图:在有n个顶点的无向图中,若有n * (n-1)/2条边,即任意两个顶点之间有且仅有一条边,
则称此图为无向完全图,比如上图G1;在n个顶点的有向图中,若有n * (n-1)条边,即任意两个
顶点之间有且仅有方向相反的边,则称此图为有向完全图,比如上图G4。

邻接顶点:在无向图中G中,若(u, v)是E(G)中的一条边,则称u和v互为邻接顶点,并称边(u,v)依附于顶点u和v;在有向图G中,若<u, v>是E(G)中的一条边,则称顶点u邻接到v,顶点v邻接自顶点u,并称边<u, v>与顶点u和顶点v相关联。

顶点的度:顶点v的度是指与它相关联的边的条数,记作deg(v)。在有向图中,顶点的度等于该顶点的入度与出度之和,其中顶点v的入度是以v为终点的有向边的条数,记作indev(v);顶点v的出度是以v为起始点的有向边的条数,记作outdev(v)。因此:dev(v) = indev(v) + outdev(v)。注
意:对于无向图,顶点的度等于该顶点的入度和出度,即dev(v) = indev(v) = outdev(v)。
路径:在图G = (V, E)中,若从顶点vi出发有一组边使其可到达顶点vj,则称顶点vi到顶点vj的顶
点序列为从顶点vi到顶点vj的路径。

路径长度:对于不带权的图,一条路径的路径长度是指该路径上的边的条数;对于带权的图,一
条路径的路径长度是指该路径上各个边权值的总和。
在这里插入图片描述
简单路径与回路:若路径上各顶点v1,v2,v3,…,vm均不重复,则称这样的路径为简单路
径。若路径上第一个顶点v1和最后一个顶点vm重合,则称这样的路径为回路或环。
在这里插入图片描述
子图:设图G = {V, E}和图G1 = {V1,E1},若V1属于V且E1属于E,则称G1是G的子图。
在这里插入图片描述
连通图:在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的。如果图中任意一对顶点都是连通的,则称此图为连通图。

强连通图:在有向图中,若在每一对顶点vi和vj之间都存在一条从vi到vj的路径,也存在一条从vj
到vi的路径,则称此图是强连通图。

生成树:一个连通图的最小连通子图称作该图的生成树。有n个顶点的连通图的生成树有n个顶点
和n-1条边。

3. 图的存储结构

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

3.1 邻接矩阵

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

  1. 无向图的邻接矩阵是对称的,第i行(列)元素之和,就是顶点i的度。有向图的邻接矩阵则不一
    定是对称的,第i行(列)元素之后就是顶点i 的出(入)度。
  2. 如果边带有权值,并且两个节点之间是连通的,上图中的边的关系就用权值代替,如果两个
    顶点不通,则使用无穷大代替。
    在这里插入图片描述
  3. 用邻接矩阵存储图的有点是能够快速知道两个顶点是否连通,缺陷是如果顶点比较多,边比
    较少时,矩阵中存储了大量的0成为系数矩阵,比较浪费空间,并且要求两个节点之间的路
    径不是很好求。

3.2 邻接矩阵的代码实现

namespace matrix
{
	template<class V, class W, W MAX = 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;//存放顶点,并建立顶点与下标的映射关系
			}

			_matrix.resize(n);
			for (int i = 0; i < _matrix.size(); i++)
			{
				_matrix[i].resize(n, MAX);
			}
		}

		size_t GetIndexMap(const V& v)
		{
			auto it = _IndexMap.find(v);
			if (it != _IndexMap.end())
				return it->second;
			else
			{
				return -1;
			}
		}

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

			_matrix[srci][dsti] = w;
			if (Direction == false)
			{
				_matrix[dsti][srci] = w;
			}
		}

		void Print()
		{
			cout <<"  ";
			for (size_t i = 0; i < _vertexs.size(); i++)
			{
				printf("%4d", i);
			}
			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)
						printf("%4c", '&');
					else
						printf("%4d", _matrix[i][j]);
				}
				cout << endl;
			}
		}

	private:
		vector<V> _vertexs;//顶点集
		map<V,int> _IndexMap;//下标和顶点映射关系
		vector<vector<W>> _matrix;//邻接矩阵
	};

	void test1()
	{
		Graph<char, int, INT_MAX, false> g("0123", 4);
		g.AddEdge('0', '0', 1);
		g.AddEdge('1', '1', 2);
		g.AddEdge('2', '2', 3);
		g.AddEdge('3', '3', 4);

		g.Print();
	}
	}

3.3 邻接表

邻接表:使用数组表示顶点的集合,使用链表表示边的关系。

  1. 无向图邻接表存储
    2.
    注意:无向图中同一条边在邻接表中出现了两次。如果想知道顶点vi的度,只需要知道顶点
    vi边链表集合中结点的数目即可。

  2. 有向图邻接表存储
    在这里插入图片描述
    注意:有向图中每条边在邻接表中只出现一次,与顶点vi对应的邻接表所含结点的个数,就
    是该顶点的出度,也称出度表,要得到vi顶点的入度,必须检测其他所有顶点对应的边链
    表,看有多少边顶点的dst取值是i。

3.4 邻接表的代码实现

namespace Link_table
{
	template<class W>
	struct Edge
	{
		W _w;
		//int _srci;
		size_t _dsti;//指向的点
		Edge<W>* _next;

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

	template<class V, class W, bool Direction = false>
	class Graph
	{
		typedef Edge<W> Edge;
	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;//存放顶点,并建立顶点与下标的映射关系
			}

			_linktable.resize(n,nullptr);
		}

		size_t GetIndexMap(const V& v)
		{
			auto it = _IndexMap.find(v);
			if (it != _IndexMap.end())
			{
				return it->second;
			}
			else
			{
				return -1;
			}
		}

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

			Edge* eg = new Edge(dsti, w);
			eg->_next = _linktable[srci];
			_linktable[srci] = eg;

			if (Direction == false)
			{
				Edge* eg = new Edge(srci, w);
				eg->_next = _linktable[dsti];
				_linktable[dsti] = eg;
			}
		}

		void Print()
		{
			for (size_t i = 0; i < _linktable.size(); i++)
			{
				cout << _vertexs[i] << "   ";
				Edge* cur = _linktable[i];
				while (cur)
				{
					cout << _vertexs[cur->_dsti] << ":" << cur->_w << "->";
					cur = cur->_next;
				}
				cout << "nullptr";
				cout << endl;
			}
		}

	private:
		vector<V> _vertexs;//顶点集
		map<V, int> _IndexMap;//下标和顶点映射关系
		vector<Edge*> _linktable;//
	};

	void test1()
	{
		string a[] = { "张三", "李四", "王五", "赵六" };
		Graph<string, int, true> g1(a, 4);
		g1.AddEdge("张三", "李四", 100);
		g1.AddEdge("张三", "王五", 200);
		g1.AddEdge("王五", "赵六", 30);
		g1.Print();
	}

	
}

4. 图的遍历

给定一个图G和其中任意一个顶点v0,从v0出发,沿着图中各边访问图中的所有顶点,且每个顶
点仅被遍历一次。"遍历"即对结点进行某种操作的意思。
请思考树以前是怎么遍历的,此处可以直接用来遍历图吗?为什么?

4.1 图的广度优先遍历

在这里插入图片描述
在这里插入图片描述

4.2 广度优先遍历的代码

namespace matrix
{
	template<class V, class W, W MAX = 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;//存放顶点,并建立顶点与下标的映射关系
			}

			_matrix.resize(n);
			for (int i = 0; i < _matrix.size(); i++)
			{
				_matrix[i].resize(n, MAX);
			}
		}

		size_t GetIndexMap(const V& v)
		{
			auto it = _IndexMap.find(v);
			if (it != _IndexMap.end())
				return it->second;
			else
			{
				return -1;
			}
		}

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

			_matrix[srci][dsti] = w;
			if (Direction == false)
			{
				_matrix[dsti][srci] = w;
			}
		}

		void BFS(const V& v)
		{
			size_t scr = GetIndexMap(v);
			queue<int> q;

			vector<bool> visited(_vertexs.size(), false);
			visited[scr] = true;
			q.push(scr);
			size_t n = _vertexs.size();
			while (!q.empty())
			{
				size_t front = q.front();
				q.pop();
				cout << front << ":" << _vertexs[front] << endl;
				for (size_t i = 0; i < n; i++)
				{
					if (_matrix[front][i] != MAX)
					{
						if (visited[i] == false)
						{
							q.push(i);
							visited[i] = true;
						}
					}
				}
			}
		}

		void Print()
		{
			cout <<"  ";
			for (size_t i = 0; i < _vertexs.size(); i++)
			{
				printf("%4d", i);
			}
			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)
						printf("%4c", '&');
					else
						printf("%4d", _matrix[i][j]);
				}
				cout << endl;
			}
		}

	private:
		vector<V> _vertexs;//顶点集
		map<V,int> _IndexMap;//下标和顶点映射关系
		vector<vector<W>> _matrix;//邻接矩阵
	};

	void test1()
	{
		Graph<char, int, INT_MAX, false> g("0123", 4);
		g.AddEdge('0', '0', 1);
		g.AddEdge('1', '1', 2);
		g.AddEdge('2', '2', 3);
		g.AddEdge('3', '3', 4);

		g.Print();
	}

	void BDFStest()
	{
		string a[] = { "张三", "李四", "王五", "赵六" };
		Graph<string, int, true> g1(a, 4);
		g1.AddEdge("张三", "李四", 100);
		g1.AddEdge("张三", "王五", 200);
		g1.AddEdge("王五", "赵六", 30);
		g1.Print();

		g1.BFS("张三");
	}
}

效果如下:
在这里插入图片描述

后面的深度优先遍历下一节继续,原因是因为这一部分挺难的,大家其实需要花很多时间去理解一下,总的来说图需要我们画很多精力去学习,相信学懂这一部分不光在代码能力上有很大提升,在逻辑思维也会有很大提升的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/905457.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

go 聊天系统项目-1

1、登录界面 说明&#xff1a;这一节的内容采用 go mod 管理【GO111MODULE‘’】的模块&#xff0c;从第二节开始使用【GO111MODULE‘off’】GOPATH 管理模块。具体参见 go 包相关知识 1.1登录界面代码目录结构 代码所在目录/Users/zld/Go-project/day8/chatroom/ 1.2登录…

支持向量机背后的数学奥秘

一、基本概念与原理 1.1 支持向量机的定义 支持向量机是一种二分类模型&#xff0c;其核心思想是在样本空间中寻找一个超平面&#xff0c;将不同类别的样本分开。这个超平面被称为决策边界或分隔超平面。支持向量是距离决策边界最近的点&#xff0c;这些点决定了决策边界的位…

C语言指针和数组相关习题

目录 sizeof和一维int数组sizeof和一维char数组strlen()和一维char数组sizeof和字符串strlen()和字符串指针变量指向字符串字面常量易错点sizeof(a):sizeof是操作符 当心整型提升sizeof和二维数组复习一下相关知识点练习题 一个离谱的错误指针1指针2指针3指针4指针5指针6指针7指…

Centos安装ZooKeeper教程(单机版)

本章教程介绍,如何在Centos7中,安装ZooKeeper 3.9.3版本。 一、什么是ZooKeeper ? Apache ZooKeeper 是一个分布式协调服务,用于大型分布式系统中的管理和协调。它为分布式应用提供了一个高性能的通信框架,简化了开发人员在构建复杂分布式系统的任务。ZooKeeper 能够解决一…

出国工作——常用英语——网站注册

Please set your password for your new Qt Account. Password must be at least 8 characters in length. 请为您的新 Qt 账户设置密码。密码长度必须至少为 8 个字符。 Password Password strength: BadThis is similar to a commonly used password. TIP: Add another wor…

江协科技STM32学习- P25 UART串口协议

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

Servlet 3.0 新特性全解

文章目录 Servlet3.0新特性全解Servlet 3.0 新增特性Servlet3.0的注解Servlet3.0的Web模块支持servlet3.0提供的异步处理提供异步原因实现异步原理配置servlet类成为异步的servlet类具体实现异步监听器改进的ServletAPI(上传文件) Servlet3.0新特性全解 tomcat 7以上的版本都支…

mysql 通过GROUP BY 聚合并且拼接去重另个字段

我的需求&#xff1a; 我想知道同一个手机号出现几次&#xff0c;并且手机号出现在哪些地方。下面是要的效果。 源数据: CREATE TABLE bank (id bigint(20) unsigned NOT NULL AUTO_INCREMENT,user_id int(11) NOT NULL DEFAULT 0,tel varchar(255) COLLATE utf8mb4_unicode_…

新加坡托管服务器VS香港托管服务器:AI时代的选择策略

在人工智能迅速发展的今天&#xff0c;服务器作为数据存储与计算的核心基础设施&#xff0c;其性能、稳定性和地理位置对于用户体验和业务效率至关重要。对于中国用户而言&#xff0c;在选择服务器时&#xff0c;新加坡服务器和香港服务器无疑是两个极具吸引力的选项。两者同属…

Linux的硬盘管理

硬盘有价&#xff0c;数据无价 1. 硬盘的概念 硬盘是一种计算机的存储设备&#xff0c;通常是由一个或者多个磁性盘片组成。硬盘即可以安装在计算机的内部&#xff0c;也可以外接计算机。 保存数据 数据&#xff1a;操作系统&#xff0c;应用程序&#xff0c;文档多媒体文件…

震惊,盖子居然重现CSDN?

盖子奇迹般重回C站 众所周知&#xff0c;盖子上次发布文章是在2024年5月18号&#xff08;感兴趣的可以回去看一下&#xff0c;链接放在下面了&#xff09; 盖子的c小课堂——第二十七讲&#xff1a;背包变形题_恰好装满的01背包-CSDN博客https://blog.csdn.net/m0_73334782/a…

PostgreSQL的学习心得和知识总结(一百五十七)|新的 COPY 选项 LOG_VERBOSITY

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

【力扣打卡系列】二叉树的最近公共祖先

坚持按题型打卡&刷&梳理力扣算法题系列&#xff0c;语言为go&#xff0c;Day18 二叉树的最近公共祖先 题目描述 解题思路 最近公共祖先分类讨论 当前节点是空节点&#xff08;返回当前节点&#xff09;当前节点是p&#xff08;返回当前节点&#xff09;当前节点是q&am…

Redis常见面试题总结(上)

Redis 基础 什么是 Redis? Redis &#xff08;REmote DIctionary Server&#xff09;是一个基于 C 语言开发的开源 NoSQL 数据库&#xff08;BSD 许可&#xff09;。与传统数据库不同的是&#xff0c;Redis 的数据是保存在内存中的&#xff08;内存数据库&#xff0c;支持持久…

Training-free layout control with cross-attention guidance

https://zhuanlan.zhihu.com/p/666445024https://zhuanlan.zhihu.com/p/666445024 支持两种模式,1.sd文生图;2.绑定了dreambooth和text inversion的图像编辑。 # ------------------ example input ------------------examples &

‌Spring MVC的主要组件有哪些?

前言 SpringMVC的核心组件包括DispatcherServlet、Controller、HandlerMapping、HandlerAdapter、ViewResolver、ModelAndView等&#xff0c;它们协同工作以支持基于MVC架构的Web应用程序开发。这些组件使得开发人员能够以一种声明式和模块化的方式构建Web应用程序&#xff0c…

Python突破浏览器TLS/JA3 指纹

初识指纹遇到一个网站,忽然发现无论如何如何更换UA和代理请求都是403&#xff0c;curl_cffi 可模拟真实浏览器的 TLS | JA3 指纹。 查看 tls 指纹的网站&#xff1a; https://tls.browserleaks.com/json不同网站的生成的指纹可能有差异&#xff0c;但是多次访问同一个网站生成…

Redis新数据类型

新数据类型 Bitmaps 命令 setbit 实例 getbit 实例 bitcount 实例 bitop 实例 Bitmaps与set 对比 HyperLogLog 命令 pfadd 实例 pfcount 实例 pfmerge 实例 Geospatial 命令 geoadd 实例 geopos 实例 geodist 实例 georadius 实例 Bitmaps Ⅰ.B…

【Qt】QTableView添加下拉框过滤条件

实现通过带复选框的下拉框来为表格添加过滤条件 带复选框的下拉框 .h文件 #pragma once #include <QCheckBox> #include <QComboBox> #include <QEvent> #include <QLineEdit> #include <QListWidget>class TableComboBox : public QComboBox …

Java Executor ScheduledExecutorService 源码

前言 相关系列 《Java & Executor & 目录》《Java & Executor & ScheduledExecutorService & 源码》《Java & Executor & ScheduledExecutorService & 总结》《Java & Executor & ScheduledExecutorService & 问题》 涉及内容 …