数据结构 图 并查集 遍历方法 最短路径算法 最小生成树算法 简易代码实现

news2024/11/26 13:53:29

文章目录

  • 前言
  • 并查集
  • 遍历方法
    • 广度优先遍历
    • 深度优先遍历
  • 最小生成树算法
    • Kruskal算法
    • Prim算法
  • 最短路径算法
    • Dijkstra算法
    • BellmanFord算法
    • FloydWarshall算法
  • 全部代码链接

前言

  1. 图是真的难,即使这些我都学过一遍,再看还是要顺一下过程;
  2. 说明方式按照 概念-> 实现思想 -> 代码逻辑 —> 代码 的方式进行 ;
  3. 图片多来自于《算法导论》 等书 ;
  4. 后续可能会做更详细的补充

并查集

概念:
并查集(Disjoint Set)是一种用于处理集合合并与查询问题的数据结构。它主要支持两种操作:合并(Union)和查找(Find)。

在并查集中,每个元素都被看作一个节点,多个节点组成一个集合。每个集合通过一个代表元素来表示,通常选择集合中的某个元素作为代表元素。

合并操作将两个不相交的集合合并成一个集合,即将其中一个集合的代表元素指向另一个集合的代表元素。

查找操作用于确定某个元素所属的集合,即找到该元素所在集合的代表元素。

通过这两种操作,可以高效地判断两个元素是否属于同一个集合,以及将不相交的集合合并成一个集合。

实现逻辑

  1. 下标代表节点
  2. 下标内的值为负代表为根节点
  3. 根节点的绝对值为该树的总节点个数
  4. 下标内的值为正值,代表的是其父亲节点的下标

在这里插入图片描述在这里插入图片描述
实现代码

// 并查集代码 
#include <vector>


class DisiointSetUnion
{
private:

	std::vector<int> _set; 

public:

	//数组下标本身就是存储的内容
	//DSU为用一维数组抽象的森林(可含多棵树)
	//默认 -1 表示默认全为单独的根节点
	DisiointSetUnion(int size)
		:_set(size, -1)
	{
		
	}
	
	//找到根节点下标
	size_t FindRoot(int x)
	{
		// 根节点存储负值,且负值的绝对值为该树节点的数量;
		// 如果不为根节点,返回其父亲节点的下标;
		while (_set[x] >= 0)
		{
			x = _set[x];
		}

		// 如果要压缩路径可在该函数内部添加后续方法

		return x; 
	}


	void Union(int x1, int x2)
	{
		int root1 = FindRoot(x1);
		int root2 = FindRoot(x2);

		if (root1 != root2)
		{
			_set[root1] += _set[root2];
			_set[ root2 ] = root1;
		}
	}
	
	//判断两节点是否一颗树中
	bool InSet(int x1, int x2)
	{
		int root1 = FindRoot(x1);
		int root2 = FindRoot(x2);

		if (root1 == root2)
		{
			return true;
		}
		else
		{
			return false;
		}
	}


	//计算有几个树
	// 通过计算负值数
	size_t SetCount()
	{
		size_t count = 0 ;
		for (size_t i = 0; i < _set.size(); i++)
		{
			if (_set[i] < 0)
			{
				count++;
			}
		}
		return count; 
	}

};

基本概念
节点(Vertex):也称为顶点,表示图中的元素。节点可以有附加的属性,如权重、颜色等。

边(Edge):表示节点之间的连接关系。边可以是有向的(有方向性)或无向的(无方向性)。有向边由起始节点指向目标节点,无向边没有方向。

路径(Path):是由边连接的节点序列。路径的长度是指路径上边的数量。

环(Cycle):是一条起始节点和终止节点相同的路径。

连通图(Connected Graph):如果图中任意两个节点之间都存在路径,则称该图为连通图。

子图(Subgraph):由图中一部分节点和边组成的图。

权重(Weight):边可以有权重,表示节点之间的关联程度或距离。

入度(In-degree)和出度(Out-degree):对于有向图,入度表示指向该节点的边的数量,出度表示从该节点出发的边的数量。

邻接点(Adjacent Vertex):与给定节点直接相连的节点

实现逻辑:
在这里插入图片描述
代码实现:

//邻接矩阵实现图
	//Direction为是否为有向图的标志位
	//INT_MAX为不存在的边的标识值
	// V 为顶点名类型 
	template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
	class Graph
	{
	private: //成员变量

		map<V, size_t> _vIndexMap; // 存储顶点名与顶点在数组中的下标   顶点名->数组中下标
		vector<V> _vertexs;		   // 存储顶点						   下标—>数组名
		vector<vector<W>> _matrix; // 图   //临界矩阵  // 此中建立边的关系

	public: //类内类


		//类内定义类,Edge类是Graph类的友元
		struct Edge
		{
			size_t _srci; // 在有向图时,为出发顶点
			size_t _dsti; // 在有向图时,为目的顶点
			W _w;    //权重

			Edge(size_t srci, size_t dsti, const W& w)
				:_srci(srci)
				, _dsti(dsti)
				, _w(w)
			{

			}

			bool operator<(const Edge& eg)
			{
				return _w < eg._w;
			}

			bool operator>(const Edge& eg)
			{
				return _w > eg._w;
			}
		};



	public: // 成员方法 

		typedef Graph<V, W, MAX_W, Direction> Self;

		Graph() = default;


		//只初始化节点,没有边
		Graph(const V* vertexs, size_t n)
		{
			_vertexs.reserve(n);

			// 对_vIndexMap 、 _vertexs 初始化
			for (size_t i = 0; i < n; ++i)
			{
				_vertexs.push_back(vertexs[i]);
				_vIndexMap[vertexs[i]] = i;
			}

			// 对 _matrix 初始化
			_matrix.resize(n);
			for (auto& e : _matrix)
			{
				e.resize(n, MAX_W);
			}
		}


		// 根据顶点名查找下标
		size_t GetVertexIndex(const V& v)
		{
			auto ret = _vIndexMap.find(v);
			if (ret != _vIndexMap.end())
			{
				return ret->second;
			}
			else
			{
				printf(" 查找顶点不存在\n");
				return -1;
			}
		}


		// 添加边,被AddEdge函数调用
		void _AddEdge(size_t srci, size_t dsti, const W& w)
		{
			//发生了越界错误  //代码的逻辑有问题 ? ? ? ? ? 
			_matrix[srci][dsti] = w;
			if (Direction == false)
			{
				_matrix[dsti][srci] = w;
			}
		}

		// 调用_AddEdge函数添加边
		void AddEdge(const V& src, const V& dst, const W& w)
		{
			size_t srci = GetVertexIndex(src);
			size_t dsti = GetVertexIndex(dst);

			_AddEdge(srci, dsti, w);
		}
	}

遍历方法

广度优先遍历

实现逻辑:
在这里插入图片描述
代码逻辑:在这里插入图片描述

代码实现:

		//测试运行成功!
		//如果为不完全连通的图怎么办???
		//src 为遍历的起始顶点
		//广度优先遍历
		//利用 队列 + 标记数组
		void BFS(const V& src)
		{
			size_t srcindex = GetVertexIndex(src);
			vector<bool> visted;
			visted.resize(_vertexs.size(), false);

			// true代表已经被遍历过
			//队列的作用类似与二叉树层序遍历中队列的作用
			queue<int> q;
			q.push(srcindex);
			visted[srcindex] = true;
			size_t d = 1;  //代表广度遍历的层数 
			size_t dSize = 1;  //队列中剩余的顶点数

			while (!q.empty())
			{

				//只有当V为基础类型时,此行代码才通用 
				cout << src << "的" << d << "度的好友 ";
				while (dSize--)
				{
					size_t front = q.front();
					q.pop();
					for (size_t i = 0; i < _matrix.size(); i++)
					{
						if (visted[i] == false && _matrix[front][i] != MAX_W)
						{
							只有当V为基础类型时,此行代码才通用
							cout << "[" << i << ":" << _vertexs[i] << "]";
							visted[i] = true;
							q.push(i);
						}
					}
				}
				cout << endl;
				dSize = q.size();
				d++;
			}
			cout << endl;
		}

深度优先遍历

实现逻辑:
在这里插入图片描述
代码实现:

//测试成功!
		// 递归实现 //思想也是类似与二叉树的递归遍历
		//深度优先遍历
		void DFS(const V& src)
		{
			size_t srcindex = GetVertexIndex(src);
			vector<bool> visted;
			visted.resize(_vertexs.size(), false);
			_DFS(srcindex, visted);
		}


		//可以遍历不连通的树吗? 
		//visited用于标志是否已经遍历过
		//深度优先遍历辅助函数
		void _DFS(size_t srcIndex, vector<bool>& visited)
		{
			cout << "[" << srcIndex << _vertexs[srcIndex] << "]";
			visited[srcIndex] = true;
			for (size_t i = 0; i < _vertexs.size(); i++)
			{
				if (visited[i] == false && _matrix[srcIndex][i] != MAX_W)
				{
					_DFS(i, visited);
				}
			}
		}

最小生成树算法

概念:
最小生成树(Minimum Spanning Tree,简称MST)是一种在连通无向图中生成一棵树的算法,使得这棵树包含了图中的所有节点,并且边的权重之和最小。

最小生成树的特点是,它是一个无环的连通子图,其中包含了图中的所有节点,并且边的权重之和最小。

Kruskal算法

概念:
Kruskal算法:Kruskal算法是一种贪心算法,它按照边的权重从小到大的顺序逐步选择边,如果选择某条边不会形成环,则将该边加入到最小生成树中,直到最小生成树中包含了所有的节点。

实现逻辑:
在这里插入图片描述
代码实现:

// Kruskal算法寻找最小生成树
		// 最小生成树是在已存在的连通图上找到把所有点连起来且总权重最小的N-1条边(N为节点总数)
		// 每次先找最小边再经判断是否构成回路确定是否连接顶点
		// 判断是否构成回路用并查集?
		// 贪心算法,寻找局部最优解  
		W Kruskal(Self& minTree)
		{
			size_t n = _vertexs.size();

			minTree._vertexs = _vertexs;
			minTree._vIndexMap = _vIndexMap;
			minTree._matrix.resize(n); // 注意深浅拷贝
			for (size_t i = 0; i < n; i++)
			{
				//! ! ! ! !
				minTree._matrix[i].resize(n, MAX_W);
			}

			//创建一个堆,用来快速找出最小路径
			priority_queue<Edge, vector<Edge>, Mygreater>  minque;
			for (size_t i = 0; i < n; i++)
			{
				for (size_t j = 0; j < n; j++)
				{
					//i < j 这个条件的原因是: 生成最小生成树的依据原图为无向图
					//最小生成树本身也是无向的
					if (i < j && _matrix[i][j] != MAX_W)
					{
						minque.push(Edge(i, j, _matrix[i][j]));
					}
				}
			}

			//开始选边 + 判是否成环
			int size = 0;  // 计算是否满足 N - 1条边的条件
			W total = W(); // 计算生成的最小生成树的总权重 
			 并查集类对象
			DisiointSetUnion dsf(n);
			while (!minque.empty())
			{
				Edge min = minque.top();
				minque.pop();
				if (!dsf.InSet(min._dsti, min._srci))
				{
					cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;
					minTree._AddEdge(min._srci, min._dsti, min._w);
					dsf.Union(min._srci, min._dsti);
					size++;
					total += min._w;
				}
				else
				{
					// 构成了环
					cout << "成环:" << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;
				}
			}

			if (size == n - 1)
			{
				return total;
			}
			else
			{
				return W();
			}

		}

Prim算法

概念:Prim算法:Prim算法也是一种贪心算法,它从一个起始节点开始,逐步选择与当前最小生成树相邻的边中权重最小的边,并将其加入到最小生成树中,直到最小生成树中包含了所有的节点。

实现逻辑:在这里插入图片描述
代码实现:

//Prim算法寻找最小生成树
		//src为生成最小生成树的起始点
		W Prim(Self& minTree, const V& src)
		{
			size_t srci = GetVertexIndex(src); // 不是给顶点名找下标的函数么……  // ! ! ! ! ! !
			size_t n = _vertexs.size(); 

			minTree._vertexs = _vertexs ;
			minTree._vIndexMap = _vIndexMap; 
			minTree._matrix.resize(n);
			for (size_t i = 0; i < n; i++)
			{
				minTree._matrix[i].resize(n, MAX_W);
			}

			// 记录是否已经被连接
			//为什么要有两个?
			vector<bool> X(n, false);
			vector<bool> Y(n, true);
			X[srci] = true; 
			Y[srci] = false;

			priority_queue<Edge, vector<Edge>, Mygreater> minq;
			for (size_t i = 0; i < n; i++)
			{
				if (_matrix[srci][i] != MAX_W)
				{
					minq.push(Edge(srci, i, _matrix[srci][i]));
				}
			}

			//开始选边



			size_t size = 0;
			W total = W();
			while (!minq.empty())
			{
				Edge min = minq.top();
				minq.pop();

				if (X[min._dsti])
				{
					//成环
				}
				else
				{
					minTree._AddEdge(min._srci, min._dsti, min._w);
					X[min._dsti] = true;
					Y[min._srci] = false;
					size++;
					total += min._w;
					if (size == n - 1)
					{
						//最多n-1条路
						break;
					}

				for (int i = 0; i < n; i++)
				{
					if (_matrix[min._dsti][i] != MAX_W && Y[i]) // ? ? ? Y[i]? ? ? 
					{
						minq.push(Edge(min._dsti, i, _matrix[min._dsti][i]));
					}
				}
			}
		}

			if (size == n - 1)
			{
				return total;
			}
			else
			{
				return W();
			}

		}

最短路径算法

概念:最短路径算法用于找到两个节点之间的最短路径,即路径上边的权重之和最小的路径。

Dijkstra算法

概念:
Dijkstra算法:Dijkstra算法是一种贪心算法,用于解决单源最短路径问题,即从一个给定的起始节点到图中所有其他节点的最短路径。算法维护一个距离数组,记录从起始节点到每个节点的当前最短距离。算法每次选择距离起始节点最近的未访问节点,并更新其邻接节点的最短距离。重复这个过程直到所有节点都被访问

注意:不可处理存在负权值的图

实现逻辑:在这里插入图片描述
代码实现:

//时间复杂度为多少 ? ? ?
		// Dijkstra 不考虑负路径的问题,或者说无法处理父权值路径的图
		//Dijkstra 为最短路径算法
		//最短路径:即计算指定出发点到任意点的距离
		// dist 记录从出发点到该点的当前已更新的最短路径,注意是当前已更新的。  dist pPath 为输出参数
		void Dijkstra(const V& src, vector<W>& dist, vector<int>& pPath)
		{
			size_t srci = GetVertexIndex(src);
			size_t n = _vertexs.size();
			dist.resize(n, MAX_W);
			pPath.resize(n, -1);

			dist[srci] = 0;
			pPath[srci] = srci;

			// 已经确定的最短路径的集合
			// 满足什么条件确定最短路径不再更新 ?  
			// 被置为true后就不会再更新吗 ?  是 
			vector<bool> S(n, false);

			for (size_t j = 0; j < n; j++)
			{
				// 1. 找出起始点直接连接的最短路径节点和其对应的权重
				// 用于记录/更新最短路径和该最短路劲对应的权重
				int u = 0;
				W min = MAX_W;

				// size_t v的for循环更新后会影响该循环结束时u的值
				for (size_t i = 0; i < n; i++)
				{
					if (S[i] == false && dist[i] < min)
					{
						u = i;
						min = dist[i];
					}
				}

				// 已选的最短路径不会再选了 
				S[u] = true;

				for (size_t v = 0; v < n; v++)
				{
					if (S[v] == false && _matrix[u][v] != MAX_W
						&& dist[u] + _matrix[u][v] < dist[v])    /* 关键 */
					{
						dist[v] = dist[u] + _matrix[u][v];
						pPath[v] = u; 
					}
				}
			}
		}

		//不可用于打印FloydWarshall的结果
		//辅助打印最短路径结果
		void PrintShortPath(const V& src, vector<W>& dist, vector<int>& pPath)
		{
			size_t srci = GetVertexIndex(src); 
			size_t n = _vertexs.size();
			for (size_t i = 0; i < n; i++)
			{
				size_t parent = pPath[i];
				cout << _vertexs[i] << "到起始顶点" << src <<"最小总权值为:" << dist[i] << "——最短路径为:";
				cout << _vertexs[i] << "<-";
				while (parent != srci)
				{
					cout << _vertexs[parent] << "<-" ;
					parent = pPath[parent];
				}
				cout  << src  << endl;
			}
		}

BellmanFord算法

概念:
Bellman-Ford算法:Bellman-Ford算法是一种动态规划算法,用于解决单源最短路径问题,可以处理带有负权边的图。算法维护一个距离数组,记录从起始节点到每个节点的当前最短距离。算法通过对所有边进行松弛操作,即尝试通过更新路径来减小距离数组中的值。重复这个过程直到没有可以更新的路径或者存在负权环。

时间复杂度分析:
Dijkstra算法适用于没有负权边的图,时间复杂度为O(V^2)或O((V + E)logV),其中V是节点数,E是边数。Bellman-Ford算法适用于带有负权边的图,时间复杂度为O(VE),其中V是节点数,E是边数。

实现逻辑:
在这里插入图片描述
代码实现:

/ BellmanFord的时间复杂度为多少 ? 如何计算的 ?
		// BellmanFord可以处理负权值路径存在的场景 
		// 关于负权值环路的问题 : 不做考虑,这种情况就没有最小权值路径,权值延着负权值环路走会无限减小,直到负无穷大
		// BellmanFord和Dijkstra的区别在于无确认该点为最短路径的这一动作 ?;
		// 停止更新的条件: 1.是依据图的最大可更新次数停止更新 ||  2.本次更新没有新的最短路径出现
		bool BellmanFord(const V& src, vector<W>& dist, vector<int>& pPath)
		{
			size_t n = _vertexs.size(); 
			size_t srci = GetVertexIndex(src); 

			dist.resize(n, MAX_W); 
			pPath.resize(n, -1);
			
			// 更新出发顶点 srci 为缺省值(0)
			dist[srci] = W();

			// 最多更新n轮 , 因为极端情况为所有顶点排成一条线
			for (size_t k = 0; k < n; ++k)
			{
				bool update = false;
				cout << "第" << k << "轮更新" << endl;
				for (size_t i = 0; i < n; ++i)
				{
					for (size_t j = 0; j < n; ++j)
					{
						// 实际上这个判断还隐含了条件 dist[i] != MAX_W ! ! ! ! ! ! !
						// 因为这个隐含条件达到了类似广度优先向外遍历更新最短路径的效果
						if (_matrix[i][j] != MAX_W && dist[i] + _matrix[i][j] < dist[j])
						{
							update = true;
							cout << _vertexs[i] << "->" << _vertexs[j] << ":" << _matrix[i][j] << endl;
							dist[j] = dist[i] + _matrix[i][j];
							pPath[j] = i;
						}
					}

					//? ? ? ? ? ? ? ?
					// 说明本次更新无新的最短路径出现,后续更新的结果也必是无效,故停止更新
					if (update == false)
					{
						break; 
					}
				}
			}

			// 判断是否存在负权回路 
			for (size_t i = 0; i < n; i++)
			{
				for (size_t j = 0; j < n; j++)
				{
					if (_matrix[i][j] != MAX_W && dist[i] + _matrix[i][j] < dist[j])
					{
						cout << "存在负权回路" << endl;
						return false; 
					}
				}
			}

			return true; 

		}

FloydWarshall算法

Floyd-Warshall算法的基本思想是通过中间节点逐步更新节点对之间的最短路径。算法维护一个二维数组D,其中D[i][j]表示节点i到节点j的最短路径长度。算法的核心是使用三重循环,对于每一对节点(i, j)和每一个可能的中间节点k,尝试更新D[i][j]的值,即通过节点k来缩短节点i到节点j的路径长度。

算法的具体步骤如下:

  1. 初始化二维数组D,将所有节点对之间的距离初始化为无穷大,但将节点自身到自身的距离初始化为0。

  2. 对于每一个中间节点k,遍历所有的节点对(i, j),尝试更新D[i][j]的值。更新的方式是比较D[i][j]的当前值和D[i][k] + D[k][j]的和,将较小的值赋给D[i][j]。

  3. 重复步骤2,对于每一个中间节点k,直到所有的节点对都被考虑过。

  4. 最终得到的二维数组D中,D[i][j]表示节点i到节点j的最短路径长度。

Floyd-Warshall算法的时间复杂度为O(V^3),其中V是节点数。由于需要遍历所有的节点对和中间节点,因此算法在处理大规模图时的效率可能较低。但它的优点是能够同时计算出所有节点对之间的最短路径,适用于需要获取全局最短路径信息的场景,例如网络路由算法中的链路状态路由协议。

实现逻辑:
在这里插入图片描述

// FloydWarshall算法求最短路径
		// vvpPath 中的值的含义为  ? ? ? 中间节点 ?   如果不存在中间节点就是指原本直接相连的点 ? 
		void FloydWarshall(vector<vector<W>>& vvDist, vector<vector<int>>& vvpPath)
		{
			size_t n = _vertexs.size(); 
			// ????
			vvDist.resize(n);
			vvpPath.resize(n);

			// 初始化
			for (size_t i = 0; i < n ; i++ )
			{
				vvDist[i].resize(n, MAX_W);
				vvpPath[i].resize(n, -1);
			}

			// ? ? ? ? ? 
			for (size_t i = 0; i < n; i++)
			{
				for (size_t j = 0; j < n; j++)
				{
					if (_matrix[i][j] != MAX_W)
					{
						vvDist[i][j] = _matrix[i][j]; 
						vvpPath[i][j] = i;
					}

					if (i == j)
					{
						vvDist[i][j] = W();
					}
					
				}
			}

			for (size_t k = 0; k < n; k++)
			{
				for (size_t i = 0; i < n; i++)
				{
					for (size_t j = 0; j < n; j++)
					{
						// k 为中间节点 !?
						if (vvDist[i][k] != MAX_W && vvDist[k][j] != MAX_W
							&& vvDist[i][k] + vvDist[k][j] < vvDist[k][j])
						{
							vvDist[i][j] = vvDist[i][k] + vvDist[k][j]; 
							vvpPath[i][j] = vvpPath[k][j]; // ! ! ! ! !
						}
					}
				}

				//打印权值和路径

				for (size_t i = 0; i < n; i++)
				{
					for (size_t j = 0; j < n; j++)
					{
						if (vvDist[i][j] == MAX_W)
						{
							printf("%3c", '*');
						}
						else
						{
							printf("%3d", vvDist[i][j]);
						}
					}
					cout << endl; 
				}
				cout << endl; 

				for (size_t i = 0; i < n; i++)
				{
					for (size_t j = 0; j < n; j++)
					{
						printf("%3d", vvpPath[i][j]);
					}
					cout << endl; 
				}

				cout << "————————————————" << endl;
			}
		}

全部代码链接

代码链接——gitee

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

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

相关文章

普通用户在Linux下免密执行sudo命令,真的可以吗?

主旨 在linux的日常运维中&#xff0c;我们会发现&#xff0c;使用root用户的权限太大了&#xff0c;很多时候一不小心就删错了&#xff0c;而且恢复不回来&#xff0c;我们应该怎么避免呢&#xff1f; 我们可以使用普通用户进行服务器的登录&#xff0c;如果有权限不够的情况&…

nodejs+vue 汽车销售系统elementui

第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性&#xff1a;技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性&#xff1a; 11 3.3性能分析 11 3.4系统操作流程 12 3.4.1管理员登录流程 12 3.4.2信息添加流程 12 3.4.3信息删除流程 13 第四章 系统设计与…

【Spring Cloud】深入理解 Eureka 注册中心的原理、服务的注册与发现

文章目录 前言一、微服务调用出现的问题1.1 服务消费者如何获取服务提供者的地址信息&#xff1f;1.2 如果有多个服务提供者&#xff0c;消费者该如何选择&#xff1f;1.3 消费者如何得知服务提供者的健康状态&#xff1f; 二、什么是 Eureka2.1 Eureka 的核心概念2.2 Eureka 的…

Python-Flask:编写自动化连接demo脚本:v1.0.0

主函数&#xff1a; # _*_ Coding : UTF-8 _*_ # Time : 13:14 # Author : YYZ # File : Flask # Project : Python_Project_爬虫 import jsonfrom flask import Flask,request,jsonify import sshapi Flask(__name__)# methods: 指定请求方式 接口解析参数host host_info[…

【已解决】 Expected linebreaks to be ‘LF‘ but found ‘CRLF‘.

问题描述 团队都是用mac&#xff0c;只有我自己是windows&#xff0c;启动项目一直报错 Expected linebreaks to be ‘LF‘ but found ‘CRLF‘. 但我不能因为自己的问题去改团队配置&#xff0c;也尝试过该vscode配置默认是LF还是报错 思路 看文章vscode如何替换所有文件的…

深度学习笔记_1、定义神经网络

1、使用了PyTorch的nn.Module类来定义神经网络模型;使用nn.Linear来创建全连接层。(CPU) import torch.nn as nn import torch.nn.functional as F from torchsummary import summary# 定义神经网络模型 class Net(nn.Module):def __init__(self):super(Net, self).__init__()…

yolov8 opencv模型部署(python版)

yolov8 opencv模型部署&#xff08;python版&#xff09; 使用opencv推理yolov8模型&#xff0c;以yolov8n为例子&#xff0c;一共几十行代码&#xff0c;没有废话&#xff0c;给出了注释&#xff0c;从今天起&#xff0c;少写一行代码&#xff0c;少掉一根头发。测试数据有需…

蓝桥等考Python组别九级001

第一部分&#xff1a;选择题 1、Python L9 &#xff08;15分&#xff09; 运行下面程序&#xff0c;可以输出几行“*”&#xff1f;&#xff08; &#xff09; for i in range(0, 7): for j in range(0, 4): print(*, end ) print() 6374 正确答案&#xff1a;C 2、P…

自动驾驶:未来的道路上的挑战与机遇

自动驾驶&#xff1a;未来的道路上的挑战与机遇 文章目录 引言安全与道路事故的减少交通拥堵的缓解城市规划的变革技术和法律挑战结语 2023星火培训【专项营】Apollo开发者社区布道师倾力打造&#xff0c;包含PnC、新感知等的全新专项课程上线了。理论与实践相结合&#xff0c;…

Qt扩展-QCustomPlot绘图基础概述

QCustomPlot绘图基础概述 一、概述二、改变外观1. Graph 类型2. Axis 坐标轴3. 网格 三、案例1. 简单布局两个图2. 绘图与多个轴和更先进的样式3. 绘制日期和时间数据 四、其他Graph&#xff1a;曲线&#xff0c;条形图&#xff0c;统计框图&#xff0c;… 一、概述 本教程使用…

Selenium 浏览器坐标转桌面坐标

背景&#xff1a; 做图表自动化项目需要做拖拽操作&#xff0c;但是selenium提供的拖拽API无效&#xff0c;因此借用pyautogui实现拖拽&#xff0c;但是pyautogui的拖拽是基于Windows桌面坐标实现的&#xff0c;另外浏览器中的坐标与windows桌面坐标并不是一比一对应的关系&am…

【计算机网络】因特网中的电子邮件

文章目录 简单邮件传送协议SMTP邮件访问协议POP3IMAPHTTP 参考资料 电子邮件为异步通信媒介 因特网电子邮件系统 电子邮件系统的三个构件&#xff1a;用户代理、邮件服务器、邮件发送和读取协议 用户代理 User Agent 即UA 电子邮件客户端软件&#xff0c;用户与电子邮件系统的接…

【从入门到起飞】JavaSE—网络编程三要素,软件架构,UDP协议

文章目录 &#x1f384;什么是网络编程&#x1f33a;常见的软件架构⭐BS架构的优缺点⭐CS架构的优缺点 &#x1f354;网络编程三要素&#x1f6f8;InetAddress类的使用⭐确定主机名称的IP地址✨查看主机名 ⭐获取此IP地址的主机名⭐返回文本显示中的IP地址字符串⭐IP&#x1f3…

Llama2-Chinese项目:3.1-全量参数微调

提供LoRA微调和全量参数微调代码&#xff0c;训练数据为data/train_sft.csv&#xff0c;验证数据为data/dev_sft.csv&#xff0c;数据格式如下所示&#xff1a; "<s>Human: "问题"\n</s><s>Assistant: "答案举个例子&#xff0c;如下所…

机器学习西瓜书+南瓜书吃瓜教程学习笔记第六章支持向量机

视频来源&#xff1a;b站直播 周志华老师机器学习西瓜树南瓜书 以下是我的学习笔记&#xff1a; 支持向量机&#xff08;support vector machines&#xff0c;SVM&#xff09;是一种二分类模型&#xff0c;它的目的是寻找一个超平面来对样本进行分割&#xff0c;分割的原则是间…

Java进阶必会JVM-深入浅出Java虚拟机

系列文章目录 送书第一期 《用户画像&#xff1a;平台构建与业务实践》 送书活动之抽奖工具的打造 《获取博客评论用户抽取幸运中奖者》 送书第二期 《Spring Cloud Alibaba核心技术与实战案例》 送书第三期 《深入浅出Java虚拟机》 文章目录 系列文章目录前言一、推荐书籍二…

LeetCode 周赛上分之旅 #48 一道简单的树上动态规划问题

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…

软件测试/测试开发丨python 多态与super 学习笔记

本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/26828 python 多态与super 多态的概念 多态&#xff1a;Polymorphism 同名方法呈现多种行为 多态的表现 号 加法&#xff1a;数字 数字拼接&#xff1a;字符串 字符串合…

2023年10月腾讯云优惠活动汇总:腾讯云最新优惠、代金券整理

腾讯云作为国内领先的云服务提供商&#xff0c;致力于为用户提供优质、稳定的云服务。为了更好地满足用户需求&#xff0c;腾讯云推出了各种优惠活动。本文将给大家分享腾讯云最新优惠活动&#xff0c;帮助用户充分利用腾讯云提供的优惠。 一、腾讯云优惠券领取【点此领取】 腾…

北京互联网公司、外企、国企大盘点

今天来盘点北京的泛互联网公司。涵盖了综合类、外企类、硬件类、电商类、游戏类、娱乐类、生活类、工具类、人工智能类、金融类、教育类、招聘类、汽车类、外包类、信息化类以及国企央企类等多个领域。 综合类 字节跳动 美团 百度 阿里巴巴 腾讯 网易 外企类 微软 谷歌 亚马逊…