探索数据结构:图(一)之邻接矩阵与邻接表

news2024/12/24 2:17:41


✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:数据结构与算法
贝蒂的主页:Betty’s blog

1. 图的定义

**图(Graph)**是数学和计算机科学中的一种基本结构,它由两个主要组成部分定义:顶点集(Vertex Set)V 边集(Edge Set)E。在一个图 G = ( V , E ) G=(V,E) G=(V,E)中,V 是顶点的有限非空集合,而 E是连接这些顶点之间的边的集合,即每条边都是两个顶点之间的关系。

  • 顶点(Vertices):顶点可以由字母变量表示,比如 V = { v 1 , v 2 , … , v n } V=\{v_1,v_2,\ldots,v_n\} V={v1,v2,,vn} n n n 表示顶点的数量,也称为图的阶或维度。
  • 边(Edges):边是表示顶点间关系的元素,通常表示为 ( u , v ) (u,v) (u,v),这意味着从顶点 u u u 到顶点 v v v 有一条边。 E E E 的大小,即 ∣ E ∣ |E| E,给出了图中边的数量。

注意:线性表有空表,树有空树,但图没有空图。也就是说图不能一个顶点没有,但是边可以为空。

2. 图的基本概念

2.1 有向图与无向图

  • 有向图中, < x , y > <x,y> <x,y>是有序的,被称为顶点x到顶点y的一条边, < x , y > <x,y> <x,y> < y , x > <y,x> <y,x>是两条不同的边。
  • 无向图中, ( x , y ) (x,y) (x,y)是无序的,称为顶点x和顶点y相关联的一条边,这条边没有特定方向, ( x , y ) (x,y) (x,y) ( y , x ) (y,x) (y,x)是同一条边。

2.2 完全图

在有n个顶点的无向图中,若有 n × ( n − 1 ) ÷ 2 n × ( n − 1 ) ÷ 2 n×(n1)÷2条边,即任意两个顶点之间都有直接相连的边,则称此图为无向完全图
在有n个顶点的有向图中,若有 n × ( n − 1 ) n × ( n − 1 ) n×(n1)条边,即任意两个顶点之间都有双向的边,则称此图为有向完全图

2.3 邻接顶点

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

2.4 顶点的度

  • 有向图中,顶点的度等于该顶点的入度与出度之和,顶点的入度是以该顶点为终点的边的条数,顶点的出度是以该顶点为起点的边的条数。
  • 无向图中,顶点的度等于与该顶点相关联的边的条数,同时也等于该顶点的入度和出度。

2.5 路径与路径长度

  • 若从顶点 v i v_i vi出发有一组边使其可到达顶点 v j v_j vj ,则称顶点 v i v_i vi到顶点 v j v_j vj 的顶点序列为从顶点 v i v_i vi到顶点 v j v_j vj 的路径。
  • 对于不带权的图,一条路径的长度是指该路径上的边的条数;对于带权的图,一条路径的长度是指该路径上各个边权值的总和。其中权值指边附带的数据信息。

2.6 简单路径与回路

  • 若路径上的各个顶点 v 1 , v 2 , v 3 . . . v n v_1,v_2,v_3...v_n v1,v2,v3...vn均不相同,则称这样的路径为简单路径
  • 若路径上第一个顶点与最后一个顶点相同,则称这样的路径为回路

2.7 子图

设图 G = ( V , E ) G=(V,E) G=(V,E)和图 G 1 = ( V 1 , E 1 ) G_1=(V_1,E_1) G1=(V1,E1),若 V 1 ⊆ V V_1⊆V V1V E 1 ⊆ E E_1⊆E E1E,那么称 G 1 G_1 G1 G G G的子图。

2.8 连通图与强连通图

  • 无向图中,若从顶点 v 1 v_1 v1 到顶点 v 2 v_2 v2 有路径,则称顶点 v 1 v_1 v1 与顶点 v 2 v_2 v2 是连通的。如果图中任意一对顶点都是连通的,则称此图为连通图
  • 有向图中,若每一对顶点 v i v_i vi v j v_j vj 之间都存在一条从 v i v_i vi v j v_j vj 的路,也存在一条从 v j v_j vj v i v_i vi 的路,则称此图是强连通图

2.9 生成树与最小生成树

  • 一个连通图的最小连通子图称为该图的生成树,有 n n n个顶点的连通图的生成树有 n n n个顶点和 n − 1 n - 1 n1条边。
  • 最小生成树指的是一个图的生成树中,总权值最小的生成树。

img

3. 图的存储结构

因为图中既有节点,又有边(节点与节点之间的关系),因此,在图的存储中,只需要保存:节点和边关系即可。 下面我们将介绍两种常见的表示方法:邻接矩阵邻接表

3.1 邻接矩阵

邻接矩阵:先用一个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系 。
对于一个具有 n n n个顶点的图 G = ( V , E ) G=(V,E) G=(V,E),其中 V V V 是顶点集, E E E 是边集。其邻接矩阵 A A A是一个 n × n n\times n n×n 的矩阵,定义如下:

  • 如果顶点 i i i 和顶点 j j j 之间有边相连,那么 A [ i ] [ j ] = 1 A[i][j]=1 A[i][j]=1(对于无向图, A [ i ] [ j ] = A [ j ] [ i ] = 1 A[i][j]=A[j][i]=1 A[i][j]=A[j][i]=1)。
  • 如果顶点 i i i 和顶点 j j j 之间没有边相连,那么 A [ i ] [ j ] = 0 A[i][j]=0 A[i][j]=0(对于无向图, A [ i ] [ j ] = A [ j ] [ i ] = 0 A[i][j]=A[j][i]=0 A[i][j]=A[j][i]=0)。

例如,对于一个简单的无向图,有三个顶点 V = { v 1 , v 2 , v 3 } V=\{v_1,v_2,v_3\} V={v1,v2,v3},如果 v 1 v_1 v1 v 2 v_2 v2 之间有边相连, v 2 v_2 v2 v 3 v_3 v3 之间有边相连, v 1 v_1 v1 v 3 v_3 v3 之间没有边相连,那么这个图的邻接矩阵为: [ 0 1 0 1 0 1 0 1 0 ] \begin{bmatrix} 0 & 1 & 0\\ 1 & 0 & 1\\ 0 & 1 & 0 \end{bmatrix} 010101010
如果是对于具有 n n n 个顶点的带权图 G = ( V , E , W ) G=(V,E,W) G=(V,E,W),其中 V V V 是顶点集, E E E 是边集, W W W 是权值集合。其邻接矩阵 A A A 是一个 n × n n\times n n×n 的矩阵。

  • 如果顶点 v i v_i vi 和顶点 v j v_j vj 之间有边相连,那么 A [ i ] [ j ] A[i][j] A[i][j] 存放着该边对应的权值。
  • 如果顶点 v i v_i vi 和顶点 v j v_j vj 之间没有边相连,那么 A [ i ] [ j ] A[i][j] A[i][j] 通常被设为一个特定的标识值,比如无穷大或者一个特殊的标记,具体取决于应用场景和算法需求。

例如,有一个带权无向图,三个顶点分别为 v 1 v_1 v1 v 2 v_2 v2 v 3 v_3 v3 v 1 v_1 v1 v 2 v_2 v2 之间边的权值为 2, v 2 v_2 v2 v 3 v_3 v3 之间边的权值为 3, v 1 v_1 v1 v 3 v_3 v3 之间没有边相连。那么这个图的邻接矩阵为: [ 0 2 ∞ 2 0 3 ∞ 3 0 ] \begin{bmatrix} 0 & 2 & ∞\\ 2 & 0 & 3\\ ∞ & 3 & 0 \end{bmatrix} 0220330

3.2 邻接表

邻接表:使用数组表示顶点的集合,使用链表表示边的关系。
对于一个具有 n n n个顶点的图 G = ( V , E ) G=(V,E) G=(V,E),邻接表的主要思想是为每个顶点建立一个链表,链表中存储与该顶点相邻的其他顶点。
具体来说:

  • 对于无向图,图中的每一条边 ( u , v ) (u,v) (u,v),如果顶点 u u u的链表中还没有顶点 v v v,则将顶点 v v v添加到顶点 u u u的链表中;同理,如果顶点 v v v的链表中还没有顶点 u u u,则将顶点 u u u添加到顶点 v v v的链表中。
  • 对于有向图,图中的每一条边 < u , v > <u,v> <u,v>,只需要将顶点 v v v添加到顶点 u u u的链表中。

例如,对于一个具有 5 5 5个顶点的无向图,顶点分别为 v 1 , v 2 , v 3 , v 4 , v 5 v_1,v_2,v_3,v_4,v_5 v1,v2,v3,v4,v5,如果有边 ( v 1 , v 2 ) (v_1,v_2) (v1,v2) ( v 1 , v 3 ) (v_1,v_3) (v1,v3) ( v 2 , v 4 ) (v_2,v_4) (v2,v4) ( v 3 , v 4 ) (v_3,v_4) (v3,v4) ( v 3 , v 5 ) (v_3,v_5) (v3,v5),那么其邻接表表示如下:

  • 顶点 v 1 v_1 v1的链表: v 2 v_2 v2 v 3 v_3 v3
  • 顶点 v 2 v_2 v2的链表: v 1 v_1 v1 v 4 v_4 v4
  • 顶点 v 3 v_3 v3的链表: v 1 v_1 v1 v 4 v_4 v4 v 5 v_5 v5
  • 顶点 v 4 v_4 v4的链表: v 2 v_2 v2 v 3 v_3 v3
  • 顶点 v 5 v_5 v5的链表: v 3 v_3 v3

如果是对于一个具有 5 5 5个顶点的有向图,顶点分别为 v 1 , v 2 , v 3 , v 4 , v 5 v_1,v_2,v_3,v_4,v_5 v1,v2,v3,v4,v5,如果有边 < v 1 , v 2 > <v_1,v_2> <v1,v2> < v 1 , v 3 > <v_1,v_3> <v1,v3> < v 2 , v 4 > <v_2,v_4> <v2,v4> < v 3 , v 4 > <v_3,v_4> <v3,v4> < v 3 , v 5 > <v_3,v_5> <v3,v5>,那么其邻接表表示如下:

  • 顶点 v 1 v_1 v1的链表: v 2 v_2 v2 v 3 v_3 v3
  • 顶点 v 2 v_2 v2的链表: v 4 v_4 v4
  • 顶点 v 3 v_3 v3的链表: v 4 v_4 v4 v 5 v_5 v5
  • 顶点 v 4 v_4 v4的链表:没有任何边。
  • 顶点 v 5 v_5 v5的链表:没有任何边。

3.3 邻接矩阵与邻接表的优缺点

对于邻接矩阵:

优点:

  • 直观性强,邻接矩阵能够 O ( 1 ) O(1) O(1)的时间判断两个顶点是否相连,并获得相连边的权值。
  • 适合稠密图:图中的边越多,邻接矩阵的空间利用率就越高。

缺点:

  • 不合适稀疏图:会浪费大量空间。
  • 不适合查找一个顶点连接出去的所有边:需要遍历矩阵中对应的一行,该过程的时间复杂度是 O ( N ) O ( N ) O(N) ,其中 N N N表示的是顶点的个数。

对于邻接表:

优点:

  • 适合查找一个顶点连接出去的所有边:只需要遍历对应的链表即可。
  • 适合稀疏图:图中的边越少,邻接表存储的空间就越少。

缺点:

  • 不合适稠密图:一个顶点会链接大量数据,需要遍历顶点对应位置的链表来确定两点是否相连,该过程的时间复杂度是 O ( E ) O(E) O(E),其中 E E E表示从源顶点连接出去的边的数量。

4. 邻接矩阵与邻接表的实现

4.1 邻接矩阵

4.1.1 邻接矩阵的结构

为了支持所有类型,我们实现一个模版类。其中肯定有两个模版参数VW分别代表顶点与权值类型,MAX_W表示两个顶点之间没有直接相连的值,一般我们默认为INT_MAX,并且还需要一个bool类型的模版参数Direction代表是有向图还是无向图,false为无向,true为有向。
邻接矩阵的成员变量有三个分别为:数组_vertexs代表边的集合,哈希表_indexMap来映射不同类型与下标的关系,二维数组_matrix代表邻接矩阵。

template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{
public:
    //构造函数
    Graph(const V*vertexs,int n);
    //获取对应顶点的下标
    int getVertexsIndex(const V& v);
    void addEdge(const V& src, const V& dest, const W& weight);
    //打印顶点集合和邻接矩阵
    void Print();
private:
    vector<V> _vertexs;//顶点集合
    unordered_map<V, int> _indexMap;//映射关系
    vector<vector<W>> _matrix;//邻接矩阵
};
4.1.2 邻接矩阵的初始化

我们首先顶点集合全部初始化,然后将邻接矩阵的值全设为INT_MAX,最后将顶点集合与下标建立映射关系。

//构造函数
Graph(const V*vertexs,int n)
    :_vertexs(vertexs, vertexs + n)
    , _matrix(n,vector<int>(n, MAX_W))
{
    //映射下标
    for (int i = 0; i < n; i++)
    {
        _indexMap[vertexs[i]] = i;
    }
}
4.1.3 添加边

添加边之前我们需要先找到对应顶点的下标,如果找不到需要抛异常。然后根据对应下标更新邻接矩阵,如果是无向图继续更新。

//获取对应顶点的下标
int getVertexsIndex(const V& v)
{
    auto it = _indexMap.find(v);
    if (it == _indexMap.end())
    {
        throw invalid_argument("不存在的顶点");
        return -1;
    }
    else
    {
        return it->second;//返回对应下标
    }
}
//添加边
void addEdge(const V& src, const V& dest, const W& weight)
{
    int srci = getVertexsIndex(src);//获取起始点下标
    int desti = getVertexsIndex(dest);//获取终点下标
    _matrix[srci][desti] = weight;
    if (Direction == false)
    {
        _matrix[desti][srci] = weight;//无向图
    }
}
4.1.4 打印邻接矩阵

最后我们打印邻接矩阵,方便测试程序的正误。

//打印顶点集合和邻接矩阵
void Print() 
{
	int n = _vertexs.size();
	//打印顶点集合
	for (int i = 0; i < n; i++) {
		cout << "[" << i << "]->" << _vertexs[i] << endl;
	}
	cout << endl;
	//打印邻接矩阵
	cout << "  ";
	for (int i = 0; i < n; i++) {
		printf("%4d", i);
	}
	cout << endl;
	for (int i = 0; i < n; i++) {
		cout << i << " "; //竖下标
		for (int j = 0; j < n; j++) {
			if (_matrix[i][j] == MAX_W) {
				printf("%4c", '*');
			}
			else {
				printf("%4d", _matrix[i][j]);
			}
		}
		cout << endl;
	}
}

4.2 邻接表

4.2.1 邻接表的结构

同样邻接表我们编写成一个模板类,相比与邻接矩阵我们可以不需要代表权值最大的MAX_W。并且为了方便描述我们需要首先编写一个关于边Edge的类。这个类包含起始与终点下标,已经对应的权值。
然后邻接表中有三个成员变量:数组_vertexs代表边的集合,哈希表indexMap来映射不同类型与下标的关系,数组_linkTable代表邻接矩阵。

template<class W>
//边
struct Edge
{
    int _srci;//起始下标
    int _desti;//终点下标
    W _w;//权值
    Edge<W>* _next;
    Edge(int srci,int desti,const W&w)
        :_srci(srci)
        ,_desti(desti)
        ,_w(w)
        ,_next(nullptr)
    {}
};
template<class V, class W, bool Direction = false>
class Graph
{
    typedef Edge<W> Edge;
public:
    //构造函数
    Graph(const V* vertexs, int n);
    //获取对应顶点的下标
    int getVertexsIndex(const V& v);
    //添加边
    void addEdge(const V& src, const V& dest, const W& weight);
    //打印顶点集合和邻接表
    void Print();
private:
    vector<V> _vertexs;//顶点集合
    unordered_map<V, int> _indexMap;//映射关系
    vector<Edge*> _linkTable;//邻接矩阵
};
4.2.2 邻接表的初始化

我们首先顶点集合全部初始化,然后将邻接表的值全设为nullptr,最后将顶点集合与下标建立映射关系;

//构造函数
Graph(const V* vertexs, int n)
    :_vertexs(vertexs, vertexs + n)
    , _linkTable(n, nullptr)
{
    //映射下标
    for (int i = 0; i < n; i++)
    {
        _indexMap[vertexs[i]] = i;
    }
}
4.2.3 添加边

添加边之前我们需要先找到对应顶点的下标,如果找不到需要抛异常。然后根据对应下标更新邻接矩阵,如果是无向图继续更新。

//获取对应顶点的下标
int getVertexsIndex(const V& v)
{
	auto it = _indexMap.find(v);
	if (it == _indexMap.end())
	{
		throw invalid_argument("不存在的顶点");
		return -1;
	}
	else
	{
		return it->second;//返回对应下标
	}
}
//添加边
void addEdge(const V& src, const V& dest, const W& weight)
{
	int srci = getVertexsIndex(src);//获取起始点下标
	int desti = getVertexsIndex(dest);//获取终点下标
	Edge* sre = new Edge(srci, desti, weight);
	//进行头插
	sre->_next = _linkTable[srci];
	_linkTable[srci] = sre;
	if (Direction == false)
	{
		Edge* dese = new Edge(desti, srci, weight);
		dese->_next = _linkTable[desti];
		_linkTable[desti] = dese;
	}
}
4.2.4 打印邻接矩阵

最后我们打印邻接表,方便测试程序的正误。

//打印顶点集合和邻接表
void Print()
{
	int n = _vertexs.size();
	//打印顶点集合
	for (int i = 0; i < n; i++) {
		cout << "[" << i << "]->" << _vertexs[i] << " ";
	}
	cout << endl << endl;

	//打印邻接表
	for (int i = 0; i < n; i++) {
		Edge* cur = _linkTable[i];
		cout << "[" << i << ":" << _vertexs[i] << "]->";
		while (cur) {
			cout << "[" << cur->_desti << ":" << _vertexs[cur->_desti] << ":" << cur->_w << "]->";
			cur = cur->_next;
		}
		cout << "nullptr" << endl;
	}
}

5. 源码

5.1 邻接矩阵

namespace Matrix
{
	template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
	class Graph
	{
	public:
		//构造函数
		Graph(const V*vertexs,int n)
			:_vertexs(vertexs, vertexs + n)
			, _matrix(n,vector<int>(n, MAX_W))
		{
			//映射下标
			for (int i = 0; i < n; i++)
			{
				_indexMap[vertexs[i]] = i;
			}
		}
		//获取对应顶点的下标
		int getVertexsIndex(const V& v)
		{
			auto it = _indexMap.find(v);
			if (it == _indexMap.end())
			{
				throw invalid_argument("不存在的顶点");
				return -1;
			}
			else
			{
				return it->second;//返回对应下标
			}
		}
		//添加边
		void addEdge(const V& src, const V& dest, const W& weight)
		{
			int srci = getVertexsIndex(src);//获取起始点下标
			int desti = getVertexsIndex(dest);//获取终点下标
			_matrix[srci][desti] = weight;
			if (Direction == false)
			{
				_matrix[desti][srci] = weight;//无向图
			}
		}
		//打印顶点集合和邻接矩阵
		void Print() {
			int n = _vertexs.size();
			//打印顶点集合
			for (int i = 0; i < n; i++) {
				cout << "[" << i << "]->" << _vertexs[i] << endl;
			}
			cout << endl;
			//打印邻接矩阵
			cout << "  ";
			for (int i = 0; i < n; i++) {
				printf("%4d", i);
			}
			cout << endl;
			for (int i = 0; i < n; i++) {
				cout << i << " "; //竖下标
				for (int j = 0; j < n; j++) {
					if (_matrix[i][j] == MAX_W) {
						printf("%4c", '*');
					}
					else {
						printf("%4d", _matrix[i][j]);
					}
				}
				cout << endl;
			}
		}
	private:
		vector<V> _vertexs;//顶点集合
		unordered_map<V, int> _indexMap;//映射关系
		vector<vector<W>> _matrix;//邻接矩阵
	};
}

5.2 邻接表

namespace LinkTable
{
	template<class W>
	struct Edge
	{
		int _srci;//起始下标
		int _desti;//终点下标
		W _w;//权值
		Edge<W>* _next;
		Edge(int srci,int desti,const W&w)
			:_srci(srci)
			,_desti(desti)
			,_w(w)
			,_next(nullptr)
		{}
	};
	template<class V, class W, bool Direction = false>
	class Graph
	{
		typedef Edge<W> Edge;
	public:
		//构造函数
		Graph(const V* vertexs, int n)
			:_vertexs(vertexs, vertexs + n)
			, _linkTable(n, nullptr)
		{
			//映射下标
			for (int i = 0; i < n; i++)
			{
				_indexMap[vertexs[i]] = i;
			}
		}
		//获取对应顶点的下标
		int getVertexsIndex(const V& v)
		{
			auto it = _indexMap.find(v);
			if (it == _indexMap.end())
			{
				throw invalid_argument("不存在的顶点");
				return -1;
			}
			else
			{
				return it->second;//返回对应下标
			}
		}
		//添加边
		void addEdge(const V& src, const V& dest, const W& weight)
		{
			int srci = getVertexsIndex(src);//获取起始点下标
			int desti = getVertexsIndex(dest);//获取终点下标
			Edge* sre = new Edge(srci, desti, weight);
			//进行头插
			sre->_next = _linkTable[srci];
			_linkTable[srci] = sre;
			if (Direction == false)
			{
				Edge* dese = new Edge(desti, srci, weight);
				dese->_next = _linkTable[desti];
				_linkTable[desti] = dese;
			}
		}
		//打印顶点集合和邻接表
		void Print()
		{
			int n = _vertexs.size();
			//打印顶点集合
			for (int i = 0; i < n; i++) {
				cout << "[" << i << "]->" << _vertexs[i] << " ";
			}
			cout << endl << endl;

			//打印邻接表
			for (int i = 0; i < n; i++) {
				Edge* cur = _linkTable[i];
				cout << "[" << i << ":" << _vertexs[i] << "]->";
				while (cur) {
					cout << "[" << cur->_desti << ":" << _vertexs[cur->_desti] << ":" << cur->_w << "]->";
					cur = cur->_next;
				}
				cout << "nullptr" << endl;
			}
		}

	private:
		vector<V> _vertexs;//顶点集合
		unordered_map<V, int> _indexMap;//映射关系
		vector<Edge*> _linkTable;//邻接矩阵
	};
}

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

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

相关文章

Mybatis-plus 创建自定义 FreeMarker 模板详细教程

FreeMarker 自定义模板官方步骤 网址&#xff1a;https://baomidou.com/reference/new-code-generator-configuration/#%E6%A8%A1%E6%9D%BF%E9%85%8D%E7%BD%AE-templateconfig &#xff08;页面往最下面拉为自定义模板相关内容&#xff09; 创建自定义FreeMarker 模板及使用…

案例分享—优秀ui设计作品赏析

多浏览国外优秀UI设计作品&#xff0c;深入分析其设计元素、色彩搭配、布局结构和交互方式&#xff0c;以理解其背后的设计理念和趋势。 在理解的基础上&#xff0c;尝试将国外设计风格中的精髓融入自己的设计中&#xff0c;同时结合国内用户的审美和使用习惯&#xff0c;进行创…

趣味算法------试用 6 和 9 组成的最大数字

目录 ​编辑 题目描述 解题思路 具体代码 总结 题目描述 给你一个仅由数字 6 和 9 组成的正整数 num。 你最多只能翻转一位数字&#xff0c;将 6 变成 9&#xff0c;或者把 9 变成 6 。 请返回你可以得到的最大数字。 输入格式 一个整数 输出格式 一个整数 输入输出…

【机器学习】决策树------迅速了其基本思想,Sklearn的决策树API及构建决策树的步骤!!!

目录 &#x1f354; 案例剖析 &#x1f354; 通过sklearn实现决策树分类并进一步认识决策树 &#x1f354; 基于规则构建决策树 &#x1f354; 构建决策树的三个步骤 &#x1f354; 小结 学习目标 &#x1f340; 了解决策树算法的基本思想 &#x1f340; 了解Sklearn的决策…

Linux WPA/WPA2/WPA3/IEEE 802.1X Supplicant

参考&#xff1a;wpa_supplicant 终端连接 wifi — Linux latest 文档 (gnu-linux.readthedocs.io) 为了管理无线网卡驱动&#xff0c;并且能正常连接到无线网络&#xff0c;你需要一个无线连接管理工具。 如何选择一个最佳的管理方法&#xff0c;将依赖于下面几个因素&#xf…

【数据结构】—— 树和二叉树

1、树的概念2、树的相关术语3、树的常见表示方法4、树的实际应用5、二叉树的相关概念和性质6、二叉树的顺序存储&#xff08;堆&#xff09;6.1 堆的概念6.2 堆的结构和接口6.3 堆的初始化和销毁6.4 堆的插入6.5 堆的删除6.5 取堆顶数据6.6 获取有效节点个数6.7 判空6.8 源代码…

免费SSL证书申请流程开启HTTPS,以及3个月到期解决方法

阿里云免费SSL证书申请流程2024年最新申请教程&#xff0c;阿里云免费SSL证书品牌是Digicert&#xff0c;免费单域名证书&#xff0c;一个阿里云账号可以免费申请20张SSL免费证书&#xff0c;免费时长为3个月&#xff08;之前是一年免费时长&#xff09;&#xff0c;免费SSL证书…

【Java并发】变量的内存存储、线程安全分析

要理解原因&#xff0c;首先要清楚局部变量是什么&#xff1f;局部变量的存储方式是什么&#xff1f; 局部变量&#xff0c;从名字上就可以知道&#xff0c;它是只在特定作用域内可见并且只能在该作用域内使用的变量。也就意味着不同作用域的局部变量是不共享的。在多线程环境下…

Apache Tomcat与反向代理

Apache Tomcat 是一个开源的 Java Servlet 容器&#xff0c;主要用于部署和运行基于 Java 的 Web 应用程序。Tomcat 提供了一个环境&#xff0c;让开发者能够使用 Java 编写的 Web 应用程序在 Web 服务器上运行。下面是对 Tomcat 的详细介绍&#xff1a; Tomcat 的历史 Tomca…

C++学习笔记——三角形面积

一、题目描述 二、代码 #include <iostream> #include <bits/stdc.h> using namespace std; int main() {double a0,b0,c0;cin >> a >> b >> c;double p(abc)/2;double dp * (p-a)* (p-b)* (p-c);cout<< fixed << setprecision(3)&l…

QT 简易网页信息抓取程序模板基础代码

有些网页爬不了&#xff0c;只是一个简单的代码。 项目结构 NetBugBaseCode.pro #------------------------------------------------- # # Project created by QtCreator 2024-08-26T15:13:10 # #-------------------------------------------------QT core gui netw…

抖音小红书爆款预定,Tiktok爆火的短视频玩法,Ai生成宝宝走秀视频,萌翻全场

大家好&#xff0c;我是方知有&#xff0c;每天分享一个互联网副业&#xff0c;喜欢的朋友可以关注~ 今天给大家分享在Tiktok爆火的短视频玩法&#xff0c;现在抖音小红书制作这类型视频的人数还不多&#xff0c;大家可以赶快操作起来&#xff0c;这个玩法就是用Ai生成宝宝走秀…

论坛测试报告1.0

版本号&#xff1a; 作者&#xff1a; 日期&#xff1a; 目录 1 引言1.1 项目概述1.2 文档概述1.2.1 编写目的1.2.2 读者对象 1.3 产品需求和设计文档 2 测试执行2.1测试工具2.2制定测试计划2.3设计测试用例2.4执行测试用例 3.测试结果4.遗留风险5.测试结果评估 1 引言 1.1 项…

【kubernetes】Pod生命周期-启动钩子、停止钩子

一&#xff0c;Pod的生命周期 pod从开始创建到终止退出的时间范围称为Pod生命周期。pod生命周期包含以下几个重要流程&#xff1a; 初始化容器&#xff08;initContainers&#xff09;。 一个pod可以拥有任意数量的init容器。init容器是按照顺序以此执行的&#xff0c;并且仅…

HAL库:中断 方式按键检测:抬起执行、按下执行、长按短按检测、延时执行

目录 HAL库&#xff1a;中断 方式按键检测&#xff1a;抬起执行、按下执行、长按短按检测、延时执行 注意事项&#xff1a; 初始化部分&#xff1a; 回调函数部分 HAL库&#xff1a;中断 方式按键检测&#xff1a;抬起执行、按下执行、长按短按检测、延时执行 注意事项&am…

如何在CMD/PowerShell中使用命令行管理IIS

使用通用IIS命令行管理工具&#xff1a; C:\Windows\System32\inetsrv\appcmd.exe 查看现有站点 1 appcmd list site 添加一个新站点 1 appcmd add site /name:"My New Site" /id:2 /bindings:http/*:81: /physicalPath:"c:\inetpub\mynewsite" /name …

559. N 叉树的最大深度(迭代法)

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果&#xff1a; 一&#xff1a;题目&#xff1a; 给定一个 N 叉树&#xff0c;找到其最大深度。 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 N 叉树输入按层序遍历…

学习系列三:V8目标检测与分割自动化标注

学习系列三&#xff1a;YOLOv8目标检测与分割自动化标注 提示&#xff1a;本次文章主要介绍yolov8目标检测与自动化标注(较简单&#xff0c;通用性比较强&#xff0c;标签格式txt)&#xff0c;yolov8实例分割与自动化标注(程序较复杂&#xff0c;自动化标注效果有待提升,标签格…

SE11 没有激活的名称表存 No active nametab exists for

背景&#xff1a; SE11中减少某个非空表的字段的长度后&#xff0c;在SE14中的操作不当&#xff0c;并且对该表进行了删除重建的操作后&#xff0c;发生SE11激活该表报错。 原因&#xff1a; 出现了一些未知原因&#xff0c;导致该表在底层数据库存在&#xff0c;但是运行时对…

柔版印刷版市场前景:预计2030年全球市场规模将达到20.9亿美元

一、当前市场状况 目前&#xff0c;柔版印刷版市场呈现出较为稳定的发展态势。随着全球经济的逐步复苏&#xff0c;包装印刷等领域对柔版印刷版的需求持续增长。柔版印刷版具有环保、高效、印刷质量高等特点&#xff0c;在食品包装、标签印刷等行业中得到广泛应用。 全球前四…