图的相关知识总结

news2024/11/24 9:25:49

目录

    • 图的概念
    • 图的存储结构
      • 邻接矩阵
      • 邻接表
    • 图的遍历
    • 最小生成树
      • Kruskal算法
      • prim算法
    • 最短路径问题
      • 单源最短路径--Dijkstra算法-
      • 单源最短路径--Bellman-Ford算法
      • 多源最短路径--Floyd-Warshall算法

图的概念

图是有顶点集合以及顶点间的关系组成的一种数据结构:G=(V,E),其中顶点集合V是有穷非空集合;
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相关联表示两点间有一条边 第k条边表示ek,ek=(vi,vj)或<vi,vj>。

有向图和无向图,有向图中边==<x,y>是有序的 <x,y>和<y,x>是不同的边,无向图中边是无序的(x,y)== (y,x)是同一条边。
完全图:在有n个顶点的无向图中,若有n*(n-1)/2条边,即任意两个顶点之间有且仅有一条边,则称此图为无向完全图;在n个顶点的有向图中,若有n*(n-1)条边,即任意两个顶点之间有且仅有方向相反的边,则称此图为有向完全图

在这里插入图片描述
邻接顶点,在无向图G中,(u,v)为图中的一条边,u和v互为邻接顶点,称边(u,v)依附于顶点u和v; 在无向图中<u,v>是图中的一条边,称点u邻接到v,v邻接自u,边<u,v>与顶点u顶点v相关联

顶点的度:顶点v的度是指与它相关联的边的条数,记作deg(v)。在有向图中,顶点的度等于该顶点的入度与出度之和,其中顶点v的入度是以v为终点的有向边的条数,记作indev(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条边。

图的存储结构

邻接矩阵

  1. 邻接矩阵就是用一个二维数组来表示所有点和边的关系,对于顶点我们用一个数组来存储,用数组下标来表示存储在该位置的顶点,二维数组matrix[i][j]是0或1 就表示vi和vj之间是否有边,为1就是从vi到vj有相连的边, 如果是带权值的边,就可以定义一个模板参数class w 默认一个最大值表示无穷大,就是vi和vj之间没有相连的边,否则vi和vj之间就有一条权值为w的边。

  2. 无向图的邻接矩阵是对称的,第i行(列)元素之和就是顶点i的度,有向图的邻接矩阵则不一定是对称的第i行(列)元素之和就是顶点i的出(入)度。

  3. 用邻接矩阵存储图的优点是能快速的知道两个顶点是否连通,缺点就是如果顶点比较多,边比较少是,矩阵中处存储了大量的0,比较浪费空间,并且要求两个节点直接的路径不是很好求。

template<class v,class w,w maxw=INT_MAX,bool Direction=false>  //顶点参数v 权值w ,布尔类型
class Graph                                                                                        //声明是否是有向图
{
	typedef Graph<v, w,maxw,Direction>self;
private:
	vector<v>vertex;   //存储所有点, 
	map<v, int>m;   //map中记录点与下标的隐射
	vector<vector<w>>matrix;  //矩阵中记录图中所有的边

public:
Graph(const v* a, size_t n)  //有参构造函数,保存所有的点,初始化保存边的二维数组
	{
		vertex.reserve(n);
		for (int i = 0; i < n; ++i)
		{
			vertex.push_back(a[i]);  //顶点建立好与下标的隐射关系
			m[a[i]] = i;
		}
		matrix.resize(n);
		for (int i = 0; i < n; ++i)
			matrix[i].resize(n, maxw);  //初始化边,矩阵中开始没有一条边,后面实现一个添加边的函数
	}
	Graph() = default;
	size_t GetIndex(const v& val)   //返回每个顶点的下标,好在矩阵中完善边的关系
	{
		
		
			if (m.find(val) != m.end())
				return m[val];
			else
			{
				throw "顶点错误";
				return -1;
			}
	}
		void _AddEdge(int src, int dest, const w& val)
	{
		matrix[src][dest] = val;
		if (Direction == false)
			matrix[dest][src] = val;
	}
	void AddEdge(const v& src, const v& dest, const w& val) //两个顶点src和dest之间有一条权值为val的边,
	{     
		size_t i = GetIndex(src);
		size_t j = GetIndex(dest);
		_AddEdge(i, j, val);  //添加进矩阵中
	}
		void print()
	{
		for (int i = 0; i < vertex.size(); ++i)
			cout << "[" << i << "]" << "->" << vertex[i] << endl;
		cout << endl;
		printf("%5c", ' ');
		for (int i = 0; i < vertex.size(); ++i)
			printf("%5d", i);
		cout << endl;
		for (int i = 0; i < vertex.size(); ++i)
		{
			printf("%5d", i);
			for (int j = 0; j < vertex.size(); ++j)
			{
				if (matrix[i][j] == INT_MAX)
					printf("%5c", '*');  //两点之间没有边就用*表示
				else
					printf("%5d", matrix[i][j]);
			}
			cout << endl;
		}
	}
}

测试邻接矩阵中初始化顶点和矩阵然后添加边,打印顶点和矩阵中记录的情况

string s = "0123";
	Graph<char, int,INT_MAX,true>gp(s.c_str(),s.size());
	try
	{
		gp.AddEdge('0', '1', 1);
		gp.AddEdge('0', '3', 4);
		gp.AddEdge('1', '3', 2);
		gp.AddEdge('1', '2', 9);
		gp.AddEdge('2', '3', 8);
		gp.AddEdge('2', '1', 5);
		gp.AddEdge('2', '0', 3);
		gp.AddEdge('3', '2', 6);
	}
	
	catch (const char* str)
	{
		cout << str << endl;
		return;
	}
	gp.print();

在这里插入图片描述

邻接表

邻接表是使用数组来存储顶点集合,同样建立顶点和下标的隐射关系,用链表来表示边的关系
下图是无向邻接表
在这里插入图片描述
无向图中同一条边在邻接表中出现了两次。想知道顶点vi的度,只需要知道顶点vi边链表集合中节点的数量即可。

对于有向图,那么我们记录每个点对应的边就分别,以该点为起点的链表就是记录了以该点为起点的所有边,所以有出边表,同理以该点为终点的记录链表就形成了入边表。

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

template<class w>     //这里我们就以出度表为例
struct Edge
{
	int dest;   //边的终点
	w _w;         //这条边的权重
	struct Edge<w>* next;  //链表指针,链表中的存储的多个dest都是起点直接相连形成的边
	Edge(int d,w we)
		:dest(d)
		,_w(we)
		,next(nullptr)
	{}
};
template<class v,class w,bool Direction=false>
class LinkGraph
{
	typedef Edge<w> Edge;
	private:
	vector<v>vertex;
	map<v, int>m;
	vector<Edge*>_table;
	public:
	LinkGraph(const v* a, size_t n)
		:vertex(a, a + n)
		,_table(n, nullptr)
	{
		for (int i = 0; i < n; ++i)
			m[a[i]] = i;
	}
	size_t getindex(const v& val)
	{
		auto it = m.find(val);
		if (it != m.end())
			return it->second;
		else
		{
			throw "顶点错误";
			return -1;
		}
	}
	void addedge(const v& x1, const v& x2,const w&we)
	{
		int src = getindex(x1);
		int dest = getindex(x2);
		Edge* e = new Edge(dest, we);
		e->next = _table[src];   //头插进以src为起点管理的链表中
		_table[src] = e;
		if (Direction == false)   //无向图 那就有两条边了
		{
			Edge* p = new Edge(src, we);
			p->next = _table[dest];
			_table[dest] = p;
		}
	}
	void print()
	{
		int n = vertex.size();
		for (int i = 0; i < n; ++i)
			cout << "[" << i << "]" << "->" << vertex[i] << endl;
		cout << endl;
		for (int i = 0; i < n; ++i)
		{
			cout << "[" << i << "]" << "->" << vertex[i] << "---";
			Edge* cur = _table[i];
			while (cur)
			{
				cout << "[" << cur->dest << "]   " << vertex[cur->dest] << "权值 " << cur->_w << "--";
				cur = cur->next;
			}
			cout << "nullptr" << endl;
		}
	}
	~LinkGraph()
	{
		for (auto e : _table)
		{
			Edge* cur = e;
			while (cur)
			{
				Edge* tail = cur->next;
				delete cur;
				cur = tail;
			}
		}
	}
};

测试邻接表

	string a[] = { "张三", "李四", "王五", "赵六" };
	LinkGraph<string, int> g1(a, 4);
	g1.addedge("张三", "李四", 100);
	g1.addedge("张三", "王五", 200);
	g1.addedge("王五", "赵六", 30);
	g1.print();

在这里插入图片描述

图的遍历

	//图的遍历   广度优先   深度优先 以在邻接矩阵中为例
	void BFS(const v& src)
	{
		int n = vertex.size();
		int sr = GetIndex(src);
		vector<bool>visited(n, false);
		queue<int>q;
		q.push(sr);
		visited[sr] = true;
		int levelsize = 1;  //可以选择记录广度优先的遍历层数
		while (!q.empty())
		{
			int size = q.size();
			while (size--)
			{
				int front = q.front();
				q.pop();
				printf("第%d层:", levelsize);
				cout << "[" << front << "]" << "->" << vertex[front] << endl;
				for (int i = 0; i < n; ++i)
				{
					if (matrix[front][i] != maxw && visited[i] == false)
					{
						q.push(i);
						visited[i] = true;
					}
				}
			}
			++levelsize;
		}
	}
	void _DFS(vector<bool>& visited, int src)  //深度优先遍历
	{
		visited[src] = true;
		cout << "[" << src << "]" << "->" << vertex[src]<<endl;
		for (int i = 0; i < vertex.size(); ++i)
		{
			if (matrix[src][i] != maxw && visited[i] == false)
				_DFS(visited, i);
		}
	}
	void DFS(const v& val)
	{
		vector<bool>visited(vertex.size(), false);
		int src = GetIndex(val);
		_DFS(visited, src);
	}

最小生成树

在这里插入图片描述

Kruskal算法

任给一个有n个顶点的连通网络N={V,E}
首先构造一个有这n个顶点组成,不含任何边的图G={V,NULL},其中每个顶点自成一个连通分量,
其次不断从E中取出权值最小的一条边(若有多条任取其一),若该边的两个顶点来自不同连通分量,则将此边加入到G中。如此重复,知道所有顶点都在同一个连通分量上为止。
核心:每次迭代时,选出一条具有最小权值,且两端点不在同一连通分量上的边,加入生成树。

   	struct Edge
	{
		int src;
		int dest;
		w _w;
		Edge(int s,int d,w we)
			:src(s)
			,dest(d)
			,_w(we)
		{}
		bool operator>(const Edge& ed)const
		{
			return _w > ed._w;
		}
	}; 
	   //全局的贪心思想
	w Kruskal(self& mintree)    //克鲁斯卡尔算法最小生成树   引用方式返回最小生成树,返回最后的总权值
	{                             //1只能使用图中的边来构造最小生成树
		int n = vertex.size();     //2只能使用恰好n-1条边来连接图中的n个顶点  依次加入权值最小的边
		mintree.vertex = vertex;   //3 选用的n-1条边不能构成回路
		mintree.m = m;             //直接将连通图里的所有边加入小堆中,在其中依次选最小边,选一条边,就将两个原本不再一个集合顶点并入一个集合,
		mintree.matrix.resize(n);   //所以要加入一条边时先判断两个顶点是否在同一集合,在就说明加入这条边就构成环了,初始时每个顶点就是一个集合
		priority_queue<Edge, vector<Edge>, greater<Edge>>pq;
		for (int i = 0; i < n; ++i)
		{
			mintree.matrix[i].resize(n, maxw);
			for (int j = 0; j < n; ++j)
			{
				if (i < j && matrix[i][j] != INT_MAX)
					pq.push(Edge(i, j, matrix[i][j]));
			}
		}
		w tatol = w();
		int i = 1;
		UnoinFind uf(n);//用到并查集 检测是否加入的边构成环,加入一条边对应的两个顶点就为一个集合,如果两个顶点已经在一个集合中则如果加入这条边就构成了环
		while (i < n && !pq.empty())
		{
			Edge ed = pq.top();
			pq.pop();
			if (!uf.Inset(ed.src, ed.dest))
			{
				uf.Unionroot(ed.src, ed.dest);
				/*printf("第%d条边:",i);
				cout << "[" << ed.src << "]" << vertex[ed.src] << "--" << "[" << ed.dest << "]" << vertex[ed.dest] <<"权值"<<ed._w<< endl;*/
				tatol += ed._w;
				mintree._AddEdge(ed.src, ed.dest, ed._w);
				++i;
			}
			else
			{    //可注释打印语句
				//cout << "[" << ed.src << "]" << vertex[ed.src] << "--" << "[" << ed.dest << "]" << vertex[ed.dest] << "构成环路" << endl;
			}
		}
		if (i == n)
			return tatol;
		else
			return w();
	}

prim算法

在这里插入图片描述

	//局部的贪心思想
	w Prim(self& mintree, const v& val)   //步骤  为了防止加入导致闭环的边,给定集合,开始只有源点一个元素,
	{                                    //从原点开始,把于该点有连接的边入小堆,选到权值最小边且终点不在集合中说明该边可以加入不会闭环,把终点加入集合
		int src = GetIndex(val);       //往外延申,以终点为起点把于其他点有链接的边且终点不在集合中的边入堆,边数加到n-1就得到了最小生成树
		mintree.vertex = vertex;
		mintree.m = m;
		int n = vertex.size();
		mintree.matrix.resize(n);
		for (int i = 0; i < n; ++i)
			mintree.matrix[i].resize(n, maxw);
		priority_queue<Edge, vector<Edge>, greater<Edge>>pq;
		vector<bool>In(n, false);
		In[src] = true;
		for (int i = 0; i < n; ++i)
		{
			if (matrix[src][i] != maxw)
				pq.push(Edge(src, i, matrix[src][i]));
		}
		int len = 1;
		w tatol = w();
		while (len < n && !pq.empty())
		{
			Edge ed = pq.top();
			pq.pop();
			if (In[ed.dest])
			{      //可注释打印语句
				//cout << "[" << ed.src << "]" << vertex[ed.src] << "--" << "[" << ed.dest << "]" << vertex[ed.dest] << "构成环路" << endl;
			}
			else
			{
				mintree._AddEdge(ed.src, ed.dest, ed._w);
				//printf("第%d条边:", len);   //打印效果语句可以注释
				//cout << "[" << ed.src << "]" << vertex[ed.src] << "--" << "[" << ed.dest << "]" << vertex[ed.dest] << "权值" << ed._w << endl;
				In[ed.dest] = true;
				tatol += ed._w;
				++len;
				for (int i = 0; i < n; ++i)
				{
					if (matrix[ed.dest][i] != maxw && In[i] == false)
						pq.push(Edge(ed.dest, i, matrix[ed.dest][i]));
				}
			}
		}
		if (len == n)
		{
			return tatol;
		}
		else
		{
			return w();
		}
	}

最短路径问题

从在带权有向图G中的某一顶点出发,找到一条通往另一顶点的最短路径,最短也就是沿路径各边权值总和达到最小

单源最短路径–Dijkstra算法-

单源最短路径问题:给定一个图G=(V,E),求源节点S∈V,到每一个结点v∈V的最短路径。Dijkstra算法就适用于解决带权重的有向图上的单源最短路径问题,同时算法要求图中所有边的权重非负。一般在求解最短路径的时候都是已知一个起点和一个终点,所以使用Dijkstra算法求解过后也就得到了所需起点到终点的最短路径。针对一个带权有向图G,将所有节点分为两组S和Q,S是已经确定最短路径的结点集合,在初始时为空(初始时就可以将源节点s放入,毕竟源节点到自己的代价是0),Q为其余未确定最短路径的结点集合,每次从Q中找出一个起点到结点代价最小的结点u,将u从Q中移出,并放入S中,对u的每一相邻结点v进行松弛操作。松弛即对每一个相邻结点v,判断源结点s到结点u的代价与u到v的代价之和是否比原来s到v的代价更小,若代价比原来小则要将s到v的代价更新为s到u和u到v的代价之和,否则维持原样。如此一直循环直至集合Q为空,即所有节点都已经查找过一遍并确定了最短路径,至于一些起点到达不了的结点在算法循环后其代价仍未初始设定的值,不发生变化。Dijkstra算法每次都是选择V-S中最小的路径节点来进行更新,并加入S中所以该算法使用的是贪心策略。存在的问题就是不支持图中带负权路径,有负权则可能找不到一些路径的最短路径。

//局部贪心思想
	void Dijkstra(const v& sr, vector<w>& dist, vector<int>& Ppath) //迪杰斯特拉算法
	{
		int src = GetIndex(sr);  //算法思想 计算源点到每个点的最短路径,用一个数组记录到该点的权值放在相应下标位置,一个数组用并查集的方式存路径
		int n = vertex.size();   //初始化 源点到源点权值为0  路径也是在相应的下标位置存他自己的下标
		dist.resize(n, maxw);    //我们在dist中找到最短路径,以该路径再去延申到其他点,更新源点到该点的权值,确定最短路径的点就不再更新了,用一个数组记录已经更新完成了的点
		Ppath.resize(n, -1);
		Ppath[src] = src;
		vector<bool>In(n, false);  //记录已经确定从源点到该点最短路径的状态标记
		dist[src] = 0;          //用 true  false 就能区分点在S集合中还是Q集合中
		for (int i = 0; i < n; ++i)//要确定到n各顶点的最短路径
		{
			int u = 0;
			int minw = maxw;
			for (int j = 0; j < n; ++j)
			{
				if (In[j] == false && dist[j] < minw) //找出还没确定最短路径的点中,目前最短的,这就已经是不能再更新的最短路径, 从这点去其他点,看路径能否更短就更新还没确定的点
				{
					u = j;      
					minw = dist[j];
				}
			}
			In[u] = true;   //这是最短的 源点到下标为u这点的最短路径就已经确定了不能再更短了,然后从这点出发比较到该点的权值加到其他点的权值是否小于源点原先到其他点的权值,小于就更新
			for (int k = 0; k < n; ++k)
			{
				if (In[k] == false && matrix[u][k] != maxw && dist[u] + matrix[u][k] < dist[k])//这里就是更新操作
				{
					dist[k] = dist[u] + matrix[u][k];
					Ppath[k] = u;    //更新了权值也就更新了该点的双亲节点,Ppath中存的是负路径,根就是源点
				}
			}
		}
	}

单源最短路径–Bellman-Ford算法

Bellman–ford算法可以解决负权图的单源最短路径问题。它的优点是可以解决有负权边的单元最短路径问题,而且可以用来判断是否有负权回路。缺点是时间复杂度O(N*E)(N是点数,E是边数)普遍是要高于Dijkstra算法O(N2)的,像这里如果使用邻接矩阵实现,那么遍历所有边的数量的时间复杂度就是O(N3),这里可以看出来Bellman_Ford就是一种暴力求解更新。

bool BellmanFord(const v& sr, vector<w>& dist, vector<int>&pPath)  //贝尔曼福特算法
	{
		int n = vertex.size();
		int src = GetIndex(sr);
		dist.resize(n, maxw);           //只要一条路径更新了就会影响包含这条路径的路径的更新
		dist[src] = 0;                 //比如  s->t 这条路径更新了  那么 s->t->z 这条路径也要更新,
		pPath.resize(n, -1);        //这里两个循环遍历所有路径算作一轮路径更新  最坏要更新n轮才能保证更新出所有点的最小路径,
		//pPath[src] = src;          //设置一个标志位,走一轮过程中有更新路径就设为真,走完一轮发现没有更新就可以break
		for (int k = 0; k < n; ++k)
		{
			bool falt = false;
			for (int i = 0; i < n; ++i)
			{
				for (int j = 0; j < n; ++j)
				{
					if (matrix[i][j] != maxw && dist[i] + matrix[i][j] < dist[j])
					{
						falt = true;
						dist[j] = dist[i] + matrix[i][j];
						pPath[j] = i;
					}
				}
			}
			if (falt == false)
				break;
		}
		for (int i = 0; i < n; ++i)
		{
			for (int j = 0; j < n; ++j)   //要考虑负权回路的问题  就是比如  a->b->c->a  本来a到a是权值为0 经过这样的回路权值变成了负值,
				                         //那这样就可以一直绕圈权值无限变小,路径永远更新不完,这种情况任何算法都无法解决,返回false
			{
				if (matrix[i][j] != maxw && dist[i] + matrix[i][j] < dist[j])
				{
					return false;      //这里再更新一轮,如果路径中没用负权回路那么前面n轮就能保证更新完,如果这里还要更新说明有负权回路就返回false
				}
			}
		}
		return true;  //这里就是正常完成
	} 

多源最短路径–Floyd-Warshall算法

在这里插入图片描述
在这里插入图片描述Floyd算法本质是在三维动态规划,D[i][j][k]表示从点i到点j只经过0到k个点最短路径,然后建立起转移方程,然后通过空间优化,优化掉最后一维度,变成一个最短路径的迭代算法,最后记得到所有点的最短路径。

	void FloydWarShall(vector<vector<w>>& vvDist, vector<vector<int>>& vvPath)  //弗洛伊德算法 计算任意两点间的最短路径
	{            //用二维数字来存个点直接最短路径的权值和,用二维数组来记录各点之间的路径
		int n = vertex.size();
		vvDist.resize(n);
		vvPath.resize(n);
		for (int i = 0; i < n; ++i)
		{                                       //初始化
			vvDist[i].resize(maxw);
			vvPath[i].resize(n, -1);
		}
		//先把直接相连的路径记录下来
		for (int i = 0; i < n; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				if (matrix[i][j] != maxw)
				{
					vvDist[i][j] = matrix[i][j];
					vvPath[i][j] = i;          //记录负路径
				}
				if (i == j)
				{
					vvDist[i][j] = w();
				}
			}
		}
		//更新路径i->j的最短路径中间经过0到k各节点 如果i->k 加上k->j的权值小于i->j权值就更新i->j 动态规划的思想
		for (int k = 0; k < n; ++k)
		{
			for (int i = 0; i < n; ++i)
			{
				for (int j = 0; j < n; ++j)
				{
					if (vvDist[i][k] != maxw && vvDist[k][j] != maxw && vvDist[i][k] + vvDist[k][j] < vvDist[i][j])
					{         //更新路径后要找到和j直接相连的上一个节点如果k直接和j相连,上一个节点就是k,如果没有直接相连上一个节点下标在pPath[k][j]中
						vvDist[i][j] = vvDist[i][k] + vvDist[k][j];
						vvPath[i][j] = vvPath[k][j];   //要注意路径的更新 一般情况 i到k i->m->k  k到j  k->h->g->j 所以更新路径此时j的双亲节点应该是g存在pPath[k][j]中
					}
				}
			}
		}
	}


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS-11A/224时间继电器 JOSEF约瑟 板前、板后接线

系列型号&#xff1a; JS-11A/11集成电路时间继电器&#xff1b;JS-11A/12集成电路时间继电器&#xff1b; JS-11A/13集成电路时间继电器&#xff1b;JS-11A/136集成电路时间继电器&#xff1b; JS-11A/137集成电路时间继电器&#xff1b;JS-11A/22集成电路时间继电器&#…

Java基础(十二)Java比较器

1 Java 比较器 我们知道基本数据类型的数据&#xff08;除boolean类型外&#xff09;需要比较大小的话&#xff0c;直接使用比较运算符即可&#xff0c;但是引用数据类型是不能直接使用比较运算符来比较大小的。那么&#xff0c;如何解决这个问题呢&#xff1f; 在Java中经常…

Jomalone(“独狼”)的Rootkit后门dll分析

从England.sys&#xff08;md5为B5F7DE342B1D661E57BCD14615CADEFA&#xff09;驱动文件中提取了4个dll文件&#xff0c;其中两个64位dll&#xff0c;两个32位dll&#xff0c;主要用于APC注入 样本的基本信息 文件名称: 0x3df60-0x15e00.dll 文件大小: 87.5 KB (89,600 字节) …

Kubeadm方式搭建K8s集群【1.23.0版本】

文章目录 一、初始化准备二、安装kubeadm三、初始化Master集群四、将新的Node节点加入集群五、部署CNI网络插件六、其他配置 Kubernetes1.24(包括1.24)之后不在兼容docker,如果有需要兼容docker的需求&#xff0c;则安装一个 cri-docker的插件&#xff0c;本文使用的是kuberne…

【SWAT水文模型】ArcSWAT输入准备

ArcSWAT输入准备 1 必需的ArcSWAT空间数据集1.1 数字高程模型&#xff08;DEM&#xff09;1.2 土地覆盖/土地利用类型1.3 土壤数据 2 可选的ArcSWAT空间数据集2.1 DEM Mask2.2 Streams2.3 User- Defined Watersheds 3 ArcSWAT表格和文本文件3.1 子流域出口位置表(dBase 表)3.2 …

【MCAL_Uart】-1.1-图文详解Uart串口协议

目录 1 什么是UART 2 UART的电平 3 UART的波特率 4 UART帧格式 4.1 start bit起始位 4.2 data bit数据位 4.3 parity bit奇偶校验位 4.4 stop bit停止位 5 什么是8-N-1 6 UART总线负载率计算 结尾 优质博文推荐阅读&#xff08;单击下方链接&#xff0c;即可跳转&am…

shell脚本基础之详解脚本的控制

详解脚本的控制 信号的处理Linux信号生成信号中断进程暂停进程 捕获信号捕获脚本退出修改或移除捕获 以后台模式运行脚本后台运行脚本运行多个后台脚本 在非控制台下运行脚本作业控制 查看作业重启停止的作业调整谦让度nice命令renice命令 定时运行作业用 at 命令来定时执行作业…

2023移动云大会即将召开,划重点来了

今年由 ChatGPT 引起的AI浪潮下&#xff0c;人们热议其背后的算力问题&#xff0c;毋庸置疑&#xff0c;算力已成为和水电同样重要的资源。作为开发者&#xff0c;如何了解云计算领域有哪些最新发展趋势&#xff1f; 4月25-26日&#xff0c;以“云擎未来&#xff0c;智信天下”…

Scala之集合(3)

目录 WordCount案例&#xff1a; 需求分析与步骤&#xff1a; 拆分&#xff1a; 聚合&#xff1a; 格式转化&#xff1a; 方法1&#xff1a; 方法2&#xff1a; 排序&#xff1a; 方法1&#xff1a; 方法2&#xff1a; 取top3&#xff1a; 整体化简后的代码&#xf…

轻量级服务器nginx:配置虚拟主机的两种方式

虚拟主机是指&#xff0c;在一台服务器中&#xff0c;通过nginx的代理&#xff0c;我们可以访问多个网站。区分不同的网站&#xff0c;可以通过端口、域名两种方式 这里写目录标题 一 端口不同区分不同的虚拟主机二 通过域名区分不同的主机名1.配置域名映射2.显示登录效果 一 …

基于ATECLOUD电源模块及单板性能自动化测试方案

一、背景介绍 客户使用直流电源、交流电源、直流负载、示波器、数据记录仪、功率分析仪、CAN卡、工控机等仪器对电源模块及单板进行功能和性能方面的测试&#xff0c;目前想要能够通过硬件自动化测试分析系统搭配对应仪器实现自动化测试&#xff0c;提升测试效率。 二、用户痛…

Linux网络——NFS共享服务

Linux网络——NFS共享服务 一、NFS共享服务1.NFS网络文件系统2.NFS 架构3.NFS 工作原理4.NFS相关配置文件及其配置作用 二、搭建NFS服务1.服务器安装 nfs-utils、rpcbind 软件包2.服务器启动nfs-utils、rpcbind服务&#xff0c;并设置共享目录3.服务端更改NFS配置&#xff0c;对…

scrapy实践-02

双师demo ptpress.com.cn/shopping/index 解析每一首歌 <ul class"f-hide"><li><a href"/song?id2037945324">芯房</a></li><li><a href"/song?id2037926385">知足</a></li><li>…

QMS-云质说质量 - 3 来料检验的九大坑,你踩过几个?

大家好&#xff0c;今天我们来讲一讲来料检验。 先重点强调一下&#xff0c;我们讨论的范围是采购大量零部件的离散制造企业&#xff0c;而不是全部类型的企业。 负责来料检验的是IQC部门。相对于整个公司的组织架构来说&#xff0c;IQC是一个很小、很小的部门。负责的事情也很…

2023找工作,怎么样才能成功跳槽面试拿到高薪呢?

前言 无论是在校招还是社会企业招聘中&#xff0c;应聘者总是要经过层层的考核才能被聘用。然而&#xff0c;在招聘时&#xff0c;设置的编程以及非技术面试问题&#xff0c;真的有必要吗&#xff1f;如此就能考核出一位开发者的真实水平&#xff1f; 说到底就是考验你的技术以…

WSL2 对外暴露端口

参考文档 一口气搞定 WSL2 的网络问题从局域网 (LAN) 访问 WSL 2 发行版通过本地网络连接到 WSL2 服务器 按照下面的操作步骤进行操作。 1. powershell 支持 sudo https://github.com/gerardog/gsudo 可以直接下载msi安装&#xff1a;https://github.com/gerardog/gsudo/rel…

excel数据分析比赛

基础 sql:百度网盘 请输入提取码 excel函数 <

Git+SpringBoot详谈

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;老茶icon &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;计…

Linux:shell+权限

索引 1.shell命令及其理解2.Linux权限及其理解1.权限基本概念2.修改权限3.权限掩码umask4.修改拥有者和所属组 3.粘滞位 1.shell命令及其理解 定义&#xff1a;命令行解释器 作用&#xff1a; 将使用者的命令翻译给kernal&#xff08;核心&#xff09;处理将核心的处理结果返…

隧道工程运维VR虚拟实操模拟训练提高学生动手能力

轨道交通作为我国国民经济的命脉和交通运输的骨干网络&#xff0c;不仅承担了绝大部分国家战略、经济物资的运输&#xff0c;还承担着客运运输职能。随着政策的重视和专业的细分&#xff0c;轨道交通的人才需求越来越大&#xff0c;但是目前传统教学面临着一些问题。 • 轨道交…