[C++]红黑树

news2024/11/18 7:23:31

一、概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。

性质:

  • 每个结点不是红色就是黑色
  • 根节点是黑色的
  • 如果一个节点是红色的,则它的两个孩子结点是黑色的
  • 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
  • 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

二、红黑树的结点定义

enum Colour
{
	RED,
	BLACK
};

template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	T _data;
	Colour _col;

	RBTreeNode(T data = T())
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_data(data)
		,_col(RED)
};

二、红黑树的插入

1、插入结点

		Node* root = GetRoot();
		if (root == nullptr)
		{
			root = new Node(data);
			root->_parent = _head;
			_head->_parent = root;

			return true;
		}

		Node* cur = root;
		Node* parent = root;
		//找到data节点插入的位置
		while (cur)
		{
			if (data < cur->_data)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (data > cur->_data)
			{
				parent = cur;
				cur = cur->_right;
			}
		}
		//插入data节点
		cur = new Node(data);
		if (data < parent->_data)
		{
			cur->_parent = parent;
			parent->_left = cur;
		}
		else
		{
			cur->_parent = parent;
			parent->_right = cur;
		}

若插入结点的父亲为黑色,则结束。

若插入结点的父亲为红色,则出现了连续的红色结点,违反规则,需要处理。 

2、调整

如插入结点后,该树违反了红黑树的规则,则对其进行调整。

(1)cur红,parent红,gparent黑,uncle存在且红

可以看出,该结点插入后,违反了规则: 如果一个节点是红色的,则它的两个孩子结点是黑色的。

此时,需要对其进行变色:将parent、uncle改为黑,gparent改为红,然后将gparent赋值给cur,若此时cur的父结点为红,则继续向上调整。

(2)cur红,parent红,gparent黑,uncle不存在

 此时cur一定是新插入的结点。否则不符合红黑树的规则:不能出现连在一起的红色结点。调整后:

 

(3)cur红,parent红,gparent黑,uncle存在且为黑

(1)基础情况 

此时cur一定不是新增结点,cur一定是由黑色变为红色的,否则就违反了红黑树的规则:每条路径黑色结点相同。

cur变红前的一种可能情况:

注:c:包含一个黑色结点的红黑树 (4种)

d/e:null或一个红色结点(4种)

调整后(旋转+变色):

我们将parent变为黑色,而非将cur变为黑色(即parent为红,cur和gparent为黑),是因为如果parent为红,那么当parent不是根结点的时候,仍需向上处理,即parent为红非终结态。

(2)单旋后转变为基础情况

对于这种情况,我们需要做以下处理:

若parent为gparent的左孩子,cur为parent的右孩子,则针对parent做左单旋转;
若parent为gparent的右孩子,cur为parent的左孩子,则针对parent做右单旋转。

旋转完成后,即转变为基础情况:

3、插入完整代码

	bool Insert(const T& data)
	{
		Node* root = GetRoot();
		if (root == nullptr)
		{
			root = new Node(data);
			root->_parent = _head;
			_head->_left = root;
			_head->_right = root;
			_head->_parent = root;
			root->_col = BLACK;
			return true;
		}

		Node* cur = root;
		Node* parent = root;
		//找到data节点插入的位置
		while (cur)
		{
			if (data < cur->_data)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (data > cur->_data)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}
		//插入data节点
		cur = new Node(data);
		if (data < parent->_data)
		{
			cur->_parent = parent;
			parent->_left = cur;
		}
		else
		{
			cur->_parent = parent;
			parent->_right = cur;
		}

		//更新_head结点链接关系
		T min = _head->_left->_data;
		T max = _head->_right->_data;
		if (data < min)
		{
			_head->_left = cur;
		}
		if (data > max)
		{
			_head->_right = cur;
		}

		//调整
		while (parent && parent->_col == RED)
		{
			Node* gparent = parent->_parent;
			

			if (parent == gparent->_left)
			{
				Node* uncle = gparent->_right;

				//cur红,parent红,gparent黑,uncle存在且红
				if (uncle && uncle->_col == RED)
				{
					//调整颜色
					parent->_col = uncle->_col = BLACK;
					gparent->_col = RED;

					//继续向上处理
					cur = gparent;
					parent = cur->_parent;
				}
				else if(uncle == nullptr)
				{
					//cur红,parent红,gparent黑,uncle不存在
					if (cur == parent->_left)
					{
						//右旋
						RotateR(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						RotateL(parent);
						RotateR(gparent);

						//变色
						cur->_col = BLACK;
						parent->_col = gparent->_col = RED;
					}

				

				}
				else if (uncle && uncle->_col == BLACK)
				{
					//cur红,parent红,gparent黑,uncle存在且为黑
					if (cur == parent->_left)
					{
						RotateR(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						//对parent左单旋后转变为上面的情况
						RotateL(parent);

						RotateR(gparent);

						//变色
						cur->_col = BLACK;
						gparent->_col = RED;
					}
				}
			}
			else if(parent = gparent->_right)
			{
				Node* uncle = gparent->_left;

				//cur红,parent红,gparent黑,uncle存在且红
				if (uncle && uncle->_col == RED)
				{
					//调整颜色
					parent->_col = uncle->_col = BLACK;
					gparent->_col = RED;

					//继续向上处理
					cur = gparent;
					parent = cur->_parent;
				}
				else if (uncle == nullptr)
				{
					//cur红,parent红,gparent黑,uncle不存在
					if (cur == parent->_right)
					{
						//左旋
						RotateL(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(gparent);

						//变色
						cur->_col = BLACK;
						parent->_col = gparent->_col = RED;

					}



				}
				else if (uncle && uncle->_col == BLACK)
				{
					//cur红,parent红,gparent黑,uncle存在且为黑
					if (cur == parent->_right)
					{
						RotateL(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						//对parent右单旋后转变为上面的情况
						RotateR(parent);

						RotateL(gparent);

						//变色
						cur->_col = BLACK;
						gparent->_col = RED;
					}
				}
			}

		}


		
		_head->_parent->_col = BLACK;
		return true;
	}

三、验证是否为红黑树

验证是否为红黑树,则需要根据红黑树的规则来确定:

没有两个连续的红色结点;

每条路径包含相同的黑色结点。

	bool IsValidRBTRee()
	{
		Node* root = GetRoot();
		if (root->_col == RED)
		{
			return false;
		}

		if (root == nullptr)
		{
			return true;
		}

		int blackc = GetBlackCount(GetRoot());
		int blacknum = 0;

		_IsValidRBTRee(GetRoot(), blackc, blacknum);
	}

	bool _IsValidRBTRee(Node* root, size_t blackCount, size_t pathBlack)
	{
		if (root == nullptr)
		{
			pathBlack++;
			if (pathBlack != blackCount)
			{
				cout << "各路径黑色结点数量不同" << endl;
				return false;
			}

			return true;
		}

		if (root->_col == RED && root->_parent->_col == RED)
		{
			return false;
		}

		if (root->_col == BLACK)
		{
			pathBlack++;
		}

		return _IsValidRBTRee(root->_left, blackCount, pathBlack)
		&& _IsValidRBTRee(root->_right, blackCount, pathBlack);

	}

四、完整代码

enum Colour
{
	RED,
	BLACK
};

template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	T _data;
	Colour _col;

	RBTreeNode(T data = T())
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_data(data)
		,_col(RED)
	{}
};


// 请模拟实现红黑树的插入--注意:为了后序封装map和set,本文在实现时给红黑树多增加了一个头结点
template<class T>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	RBTree()
	{
		_head = new Node;
		_head->_left = _head;
		_head->_right = _head;
		_head->_parent = _head;
	}


	// 在红黑树中插入值为data的节点,插入成功返回true,否则返回false
	// 注意:为了简单起见,本次实现红黑树不存储重复性元素
	bool Insert(const T& data)
	{
		Node* root = GetRoot();
		if (root == nullptr)
		{
			root = new Node(data);
			root->_parent = _head;
			_head->_left = root;
			_head->_right = root;
			_head->_parent = root;
			root->_col = BLACK;
			return true;
		}

		Node* cur = root;
		Node* parent = root;
		//找到data节点插入的位置
		while (cur)
		{
			if (data < cur->_data)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (data > cur->_data)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}
		//插入data节点
		cur = new Node(data);
		if (data < parent->_data)
		{
			cur->_parent = parent;
			parent->_left = cur;
		}
		else
		{
			cur->_parent = parent;
			parent->_right = cur;
		}

		//更新_head结点链接关系
		T min = _head->_left->_data;
		T max = _head->_right->_data;
		if (data < min)
		{
			_head->_left = cur;
		}
		if (data > max)
		{
			_head->_right = cur;
		}

		//调整
		while (parent && parent->_col == RED)
		{
			Node* gparent = parent->_parent;
			

			if (parent == gparent->_left)
			{
				Node* uncle = gparent->_right;

				//cur红,parent红,gparent黑,uncle存在且红
				if (uncle && uncle->_col == RED)
				{
					//调整颜色
					parent->_col = uncle->_col = BLACK;
					gparent->_col = RED;

					//继续向上处理
					cur = gparent;
					parent = cur->_parent;
				}
				else if(uncle == nullptr)
				{
					//cur红,parent红,gparent黑,uncle不存在
					if (cur == parent->_left)
					{
						//右旋
						RotateR(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						RotateL(parent);
						RotateR(gparent);

						//变色
						cur->_col = BLACK;
						parent->_col = gparent->_col = RED;
					}

				

				}
				else if (uncle && uncle->_col == BLACK)
				{
					//cur红,parent红,gparent黑,uncle存在且为黑
					if (cur == parent->_left)
					{
						RotateR(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						//对parent左单旋后转变为上面的情况
						RotateL(parent);

						RotateR(gparent);

						//变色
						cur->_col = BLACK;
						gparent->_col = RED;
					}
				}
			}
			else if(parent = gparent->_right)
			{
				Node* uncle = gparent->_left;

				//cur红,parent红,gparent黑,uncle存在且红
				if (uncle && uncle->_col == RED)
				{
					//调整颜色
					parent->_col = uncle->_col = BLACK;
					gparent->_col = RED;

					//继续向上处理
					cur = gparent;
					parent = cur->_parent;
				}
				else if (uncle == nullptr)
				{
					//cur红,parent红,gparent黑,uncle不存在
					if (cur == parent->_right)
					{
						//左旋
						RotateL(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(gparent);

						//变色
						cur->_col = BLACK;
						parent->_col = gparent->_col = RED;

					}



				}
				else if (uncle && uncle->_col == BLACK)
				{
					//cur红,parent红,gparent黑,uncle存在且为黑
					if (cur == parent->_right)
					{
						RotateL(gparent);
						//变色
						parent->_col = BLACK;
						gparent->_col = RED;
					}
					else
					{
						//对parent右单旋后转变为上面的情况
						RotateR(parent);

						RotateL(gparent);

						//变色
						cur->_col = BLACK;
						gparent->_col = RED;
					}
				}
			}

		}


		
		_head->_parent->_col = BLACK;
		return true;
	}

	// 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
	Node* Find(const T& data)
	{
		Node* cur = GetRoot();
		Node* parent = cur;

		while (cur)
		{
			if (data > cur->_data)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (data < cur->_data)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}

		return nullptr;
	}

	// 获取红黑树最左侧节点
	Node* LeftMost()
	{
		return _head->_left;
	}

	// 获取红黑树最右侧节点
	Node* RightMost()
	{
		return _head->_right;
	}

	// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
	bool IsValidRBTRee()
	{
		Node* root = GetRoot();
		if (root->_col == RED)
		{
			return false;
		}

		if (root == nullptr)
		{
			return true;
		}

		int blackc = GetBlackCount(GetRoot());
		int blacknum = 0;

		_IsValidRBTRee(GetRoot(), blackc, blacknum);
	}

	void InOrder()
	{
		_InOrder(GetRoot());
	}
private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_InOrder(root->_left);
		cout << root->_data << " ";
		_InOrder(root->_right);
	}

	size_t GetBlackCount(Node* root)
	{
		size_t ret = 0;
		Node* cur = root;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				ret++;
			}
			cur = cur->_left;
		}
		ret++;

		return ret;
	}

	bool _IsValidRBTRee(Node* root, size_t blackCount, size_t pathBlack)
	{
		if (root == nullptr)
		{
			pathBlack++;
			if (pathBlack != blackCount)
			{
				cout << "各路径黑色结点数量不同" << endl;
				return false;
			}

			return true;
		}

		if (root->_col == RED && root->_parent->_col == RED)
		{
			return false;
		}

		if (root->_col == BLACK)
		{
			pathBlack++;
		}

		return _IsValidRBTRee(root->_left, blackCount, pathBlack)
		&& _IsValidRBTRee(root->_right, blackCount, pathBlack);

	}


	// 右单旋
	void RotateR(Node* parent)
	{
		Node* pprent = parent->_parent;
		Node* pl = parent->_left;
		Node* PRL = pl->_right;
		Node* PR = parent;

		//更新与上一节点的链接关系
		if (parent == GetRoot())
		{
			_head->_parent = pl;
			pl->_parent = nullptr;
		}
		else
		{
			if (pprent->_left == parent)
			{
				pprent->_left = pl;
			}
			else
			{
				pprent->_right = pl;
			}

			pl->_parent = pprent;
		}


		pl->_right = PR;
		PR->_parent = pl;
		PR->_left = PRL;
		if (PRL)
			PRL->_parent = PR;

	}

	// 左单旋
	void RotateL(Node* parent)
	{
		Node* pprent = parent->_parent;
		Node* pr = parent->_right;
		Node* PLR = pr->_left;
		Node* PL = parent;

		//更新与上一节点的链接关系
		if (parent == GetRoot())
		{
			_head->_parent = pr;
			pr->_parent = nullptr;
		}
		else
		{
			if (pprent->_left == parent)
			{
				pprent->_left = pr;
			}
			else
			{
				pprent->_right = pr;
			}

			pr->_parent = pprent;

		}


		pr->_left = PL;
		PL->_parent = pr;
		PL->_right = PLR;
		if (PLR)
			PLR->_parent = PL;

	}
	// 为了操作树简单起见:获取根节点
	Node* GetRoot()
	{
		if (_head->_parent == _head)
		{
			return nullptr;
		}
		else
		{
			return _head->_parent;
		}
	}
private:
	Node* _head;
};

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

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

相关文章

配置阿里yum源

配置阿里yum源&#xff08;这个很重要&#xff09;&#xff1a;https://developer.aliyun.com/article/1480470 1.备份系统自带yum源配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup2.下载ailiyun的yum源配置文件 2.1 CentOS7 wge…

【Vue】响应式特性

响应式&#xff1a;简单理解就是数据改变&#xff0c;视图会自动更新。 如何访问 和 修改 data中的数据&#xff08;响应式演示&#xff09; data中的数据, 最终会被添加到实例上 例如这里&#xff0c;app身上就会拥有msg属性&#xff0c;修改msg的值&#xff0c;界面的值也会…

Deepin Linux 深度 V23 beige 官方源及换镜像源方法。

Deepin Linux 深度 V23 英文版本号&#xff1a;beige 谁起的烂名字。。。。。。 1. 打开文件管理器&#xff0c;在apt文件夹点右键&#xff08;以管理员身份打开&#xff09;&#xff0c; 2. 输入你的登录密码&#xff0c;以便打开文件夹&#xff08;管理员权限&#xff09;。…

成都市酷客焕学新媒体科技有限公司:助力品牌打破困境!

在数字化浪潮的推动下&#xff0c;营销策略对品牌的发展愈发关键。成都市酷客焕学新媒体科技有限公司&#xff0c;作为短视频营销领域的佼佼者&#xff0c;凭借其卓越的策略和实力&#xff0c;助力众多品牌在信息海洋中脱颖而出&#xff0c;实现品牌的显著增长。 酷客焕学专注于…

【机器学习】基于tensorflow实现你的第一个DNN网络

博客导读&#xff1a; 《AI—工程篇》 AI智能体研发之路-工程篇&#xff08;一&#xff09;&#xff1a;Docker助力AI智能体开发提效 AI智能体研发之路-工程篇&#xff08;二&#xff09;&#xff1a;Dify智能体开发平台一键部署 AI智能体研发之路-工程篇&#xff08;三&am…

学习sam的过程

一、抓包 我平时都是用花瓶去抓包的&#xff0c;配置也很简单。就是下载软件&#xff0c;然后一步步安装。下载地址&#xff1a;Download a Free Trial of Charles • Charles Web Debugging Proxy 。然后配置手机代理 对于那些走http协议的app是可以的&#xff0c;https的还是…

【记录】打印|无需排版,生成证件照打印PDF,打印在任意尺寸的纸上(简单无损!)

以前我打印证件照的时候&#xff0c;我总是在网上找在线证件照转换或者别的什么。但是我今天突然就琢磨了一下&#xff0c;用 PDF 打印应该也可以直接打印出来&#xff0c;然后就琢磨出来了&#xff0c;这么一条路大家可以参考一下。我觉得比在线转换成一张 a4 纸要方便的多&am…

视频智能分析平台LntonAIServer视频监控管理平台裸土检测算法的重要性与应用

随着科技的飞速发展&#xff0c;人工智能技术在各个领域的应用越来越广泛。其中&#xff0c;LntonAIServer裸土检测算法作为一种先进的技术手段&#xff0c;已经在农业、环境保护等领域取得了显著的成果。本文将探讨LntonAIServer裸土检测算法的重要性及其在实际应用中的优势。…

git新电脑下载配置记录

1、官网下载 2、安装 3、配置 &#xff08;1&#xff09;先生成密钥 ssh-keygen -t rsa -C “XXXqq.com” &#xff08;2&#xff09;生成两个文件&#xff0c;复制.pub,在GitHub的setting里面设置ssh&#xff0c; &#xff08;3&#xff09;验证远程是否配置成功 ssh -T g…

【工具使用】在vscode中用python绘图

安装拓展Jupyter Keymap 然后重启vscode在代码之前加上这个代码&#xff0c;利用jupyter一行一行运行 # %%点击Run Cell即可运行 # %% import matplotlib.pyplot as plt# 提供的数据 data [0.02856750446367257, 0.248564674096589, 0.1645266594124048, 0, 0.375108941955725…

JavaSE——类和对象(三)~~继承

目录 一.继承 1.为什么需要继承 2 .继承概念 3.继承的语法格式 4.继承的特性及好处 5.父类成员访问 6.继承关系上的代码块执行顺序​​​​​​​ 二.继承与组合 一.继承 1.为什么需要继承 Java中使用类对现实世界中实体来进行描述&#xff0c;类经过实例化之后的产物…

前端破圈用Docker开发项目

为什么要用 Docker 开发 &#x1f914; 直接在系统上开发不香吗&#xff1f;香&#xff0c;但是 Docker 有下面4香 环境依赖管理&#xff1a;Docker 容器可以管理所有依赖项&#xff0c;例如前端里面的 node 和 npm 版本&#xff0c;不需要在本地安装和维护这些依赖项 隔离&a…

【WEEK14】 【DAY2】Shiro第七部分【中文版】

2024.5.28 Tuesday 接上文【WEEK14】 【DAY1】Shiro第六部分【中文版】 目录 15.8.Shiro整合Thymeleaf15.8.1.修改pom.xml添加依赖15.8.1.1.shiro-thymeleaf整合包导入15.8.1.2.当前完整的pom文件 15.8.2.修改ShiroConfig.java15.8.3.修改index.html15.8.4.给root用户开放所有权…

Java 构造方法的作用以及如何重载构造方法

Java是一种面向对象的编程语言&#xff0c;其中对象是核心概念之一。每个对象都由类创建&#xff0c;而类是对象的蓝图。为了创建和初始化对象&#xff0c;Java引入了构造方法&#xff08;Constructors&#xff09;。 构造方法的作用 构造方法是与类同名的特殊方法&#xff0…

代理注册湖北武汉投资管理公司流程和条件

我公司代理注册湖北武汉投资管理公司&#xff0c;现在大家都知道全国的投资管理公司已经停批了&#xff0c;很多需要收购的老板都是通过收购现成的投资管理公司经营的&#xff0c;现在我告诉大家一个好消息&#xff0c;我们有渠道办理湖北武汉资产管理公司&#xff0c;详情致电…

《Intel开发手册卷3》读书笔记3

1、中断和异常的概述 中断和异常是强制性的执行流的转移&#xff0c;从当前正在执行的程序或任务转移到一个特殊的称作句柄的例程或任务。当硬件发出信号时&#xff0c;便产生中断&#xff0c;中断的产生同正在执行的程序是异步的&#xff0c;即中断的产生是随机的。其用于处理…

【YOLOv10】使用yolov10训练自己的数据集/验证 /推理 /导出模型/ONNX模型的使用

YOLOv10: 实时端到端的目标检测。 性能 YOLOv10比最先进的YOLOv9延迟时间更低&#xff0c;测试结果可以与YOLOv9媲美&#xff0c;可能会成为YOLO系列模型部署的“新选择”。 目录 1 数据准备 2 配置文件 3 训练 4 验证 5 预测 6 导出模型 7 ONNX模型的使用 官方论文地址…

AI新时代——【深度学习】驱动的【AIGC大模型】与【机器学习】的创新融合

目录 1.机器学习与人工智能的基础 1.机器学习的基本原理 2.人工智能的广泛应用 2.深度学习的崛起 1.深度学习的概念和原理 2.卷积神经网络&#xff08;CNN&#xff09; 3.循环神经网络&#xff08;RNN&#xff09; 3.AIGC大模型的创新 1.AIGC的概念和应用 2.代表性AI…

【手把手带你微调 Llama3】 改变大模型的自我认知,单卡就能训

微调Llama3的自我认知后 当你问Llama3中文问题&#xff1a; “你叫什么名字&#xff1f;”、 “做个自我介绍”、 “你好” Llama3 会用中文回答 &#xff1a; “我是AI在手” &#xff08;如下图&#xff09; 1、环境安装 # nvidia 显卡 显存16G# pytorch 2.2.2 …

【全球展会招商】2025COSP深圳国际户外展乘风而至,启赴新程!

展会介绍 “2025-COSP深圳国际户外展览会”将于展出面积达40,000㎡&#xff0c;展出品牌60家包含户外露营展区、 车旅生活展区 、户外运动展区、水上运动展区 、 民宿旅居展区等热门产品专区&#xff0c;充分满足供应商及采购商、行业人士及运动爱好者的需求&#xff0c;打造展…