当前位置: 首页 > news >正文

[数据结构]-红黑树

前言

作者小蜗牛向前冲

名言:我可以接受失败,但我不能接受放弃

  如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正

目录

一、红黑树的基本知识

 1、红黑树的概念

2、性质 

二、红黑树的模拟实现 

1、节点的定义

2、红黑树的插入 

三、红黑树的测试

1、验证的准备工作

2、测试用例 

3、完整代码实现 

四、AVL树和红黑树的比较 


本期学习目标:什么是红黑树,红黑树是怎么实现的,红黑树的测试,红黑树和AVL树的对比 

一、红黑树的基本知识

 1、红黑树的概念

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

2、性质 

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

 推论:

  1. 最短路径:全部由黑节点组成
  2. 最长路径:一黑一红,红节点数量 == 黑节点数量

这里我们思考一下,红黑树是如何保证:最长路径不超过最短路径的2倍?

  • 由推论2可知,对于最长路经,就是一红一黑,而且红节点数量等于黑节点数量,
  • 在由推论1可知,最短路径节点数量全为黑。
  • 在由性质4可知,每条路径的黑节点数量都相同,这就保证了最长路径不超过2倍的最短路径。

二、红黑树的模拟实现 

1、节点的定义

enum Colour
{RED,BLACK,
};template<class K,class V>
struct RBTreeNode
{pair<K, V> _kv;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Colour _col;RBTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_col(RED){}
};

2、红黑树的插入 

根据节点的定义,我们上面定义了一个枚举类型了存放显色的类型,RED和BLACK,但是我们在插入节点的时候是定义红色还是黑色呢?我们在上面定义的是红色为什么呢?

这里分类讨论一下:

定义新插入节点为黑色

就会破坏性质4,导致每天路径的黑色节点数量不同

定义新插入节点为红色

可能会破坏性质3,导致出现连续的红节点,但是这样也仅仅影响的是一条路径,影响有限。

综上所述:所以我们选择插入节点为红色。

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

1. 按照二叉搜索的树规则插入新节点

2.检测新节点插入后,红黑树的性质是否造到破坏

因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点(p:parent g:grandfather u:uncle)

当p为g的左孩子时,有3种情况需要讨论

情况1:

 

 情况2:

情况3:

 当p为g的右孩子时,也有3种情况需要讨论

这里的讨论和上面相似,处理方法也相似:

情况1:

情况2: 

情况3:

代码实现:

bool insert(const pair<K, V>& kv)
{if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;return true;}//找到插入位置Node* parent = nullptr;Node* cur = _root;while (cur){//到左子树找if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}//找到了cur = new Node(kv);cur->_col = RED;//默认颜色为红色//链接节点if (parent->_kv.first > kv.first){parent->_left = cur;cur->_parent = parent;}else{parent->_right = cur;cur->_parent = parent;}//插入后要调整红黑树//如果父亲存在且为红色while (parent && parent->_col == RED){Node* grandparent = parent->_parent;//情况1:cur为红色,p和u都为红色,g为黑色,这里的u是存在的//解决方法:p和n都变黑,g变红,在把cur当做g继续调整if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;//更新parentparent = cur->_parent;}else//情况2+3  uncle存在且为黑色或者uncle不存在{if (cur == parent->_left){//情况2//解决方法:右单旋,将p变黑,g变红RotateR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}else//情况3:双旋转{RotateL(parent);RotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;//双旋转后cur变为了根}//这里类比根节点为色,不需要在调整了break;}}else//grandparent->right == parent{//这里也是和上面一样分为三种情况Node* grandparent = parent->_parent;Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;//更新parentparent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);//左单旋转parent->_col = BLACK;grandparent->_col = RED;}else{RotateR(parent);RotateL(grandparent);grandparent->_col = RED;cur->_col = BLACK;//双旋转后cur变为了根}break;}}}//调整完成,把根节点变黑_root->_col = BLACK;return true;
}
//右单旋
void RotateR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;Node* grandparent = parent->_parent;//让subLR变为parent的左,parent->_left = subLR;//这里要判断一下subLR不为空if (subLR){subLR->_parent = parent;}//parent变为subL的右subL->_right = parent;parent->_parent = subL;//parent就是为根if (grandparent == nullptr){_root = subL;subL->_parent = grandparent;}else{//parnet是上grandparent的左子树if (grandparent->_left == parent){grandparent->_left = subL;}else{grandparent->_right = subL;}subL->_parent = grandparent;}
}//左单旋
void RotateL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;Node* ppNode = parent->_parent;parent->_right = subRL;if (subRL){subRL->_parent = parent;}subR->_left = parent;parent->_parent = subR;//parnet为根,要更新根if (ppNode == nullptr){_root = subR;subR->_parent = ppNode;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}
}

三、红黑树的测试

1、验证的准备工作

  1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)

  2. 检测其是否满足红黑树的性质
    检测方法:
    1、根节点是黑色,否则不是红黑树
    2、当前节点是红色,去检测父亲节点,父亲节点也是红色,则不是红黑树
    3、以最左侧路径的黑色节点为基准,其它路径上的黑色节点与基准不相等,不是红黑树

 检验代码:

void Inorder()
{_Inorder(_root);
}void _Inorder(Node* root)
{if (root == nullptr)return;_Inorder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_Inorder(root->_right);
}bool Check(Node* root, int blackNum, const int ref)
{if (root == nullptr){//已经递归到最深处进行,本路径的黑节点树和ref数量对比if (blackNum != ref){cout << "违反规则:本条路径的黑色节点的数量跟最左路径不相等" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){cout << "违反规则:出现连续红色节点" << endl;return false;}if (root->_col == BLACK){++blackNum;}return Check(root->_left, blackNum, ref)&& Check(root->_right, blackNum, ref);
}bool IsBalance()
{if (_root == nullptr){return true;}if (_root->_col != BLACK){return false;}//求出最左路节点有多少个黑节点int ref = 0;Node* left = _root;while (left){if (left->_col == BLACK){++ref;}left = left->_left;}return Check(_root, 0, ref);
}

2、测试用例 

这里我们借用上面AVL树的测试用例即可

void TestRBTree1()
{//int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };RBTreeh<int, int> t;for (auto e : a){/*if (e == 18){int x = 0;}*/t.insert(make_pair(e, e));cout << "insert" << e << ":" << t.IsBalance() << endl;}t.Inorder();cout << t.IsBalance() << endl;
}void TestRBTree2()
{srand(time(0));const size_t N = 100000;RBTreeh<int, int> t;for (size_t i = 0; i < N; ++i){size_t x = rand();t.insert(make_pair(x, x));//cout << t.IsBalance() << endl;}//t.Inorder();cout << t.IsBalance() << endl;
}

3、完整代码实现 

#pragma onceenum Colour
{RED,BLACK,
};template<class K,class V>
struct RBTreeNode
{pair<K, V> _kv;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Colour _col;RBTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_col(RED){}
};template<class K,class V>
class RBTreeh
{typedef RBTreeNode<K,V> Node;
public:bool insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;return true;}//找到插入位置Node* parent = nullptr;Node* cur = _root;while (cur){//到左子树找if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}//找到了cur = new Node(kv);cur->_col = RED;//默认颜色为红色//链接节点if (parent->_kv.first > kv.first){parent->_left = cur;cur->_parent = parent;}else{parent->_right = cur;cur->_parent = parent;}//插入后要调整红黑树//如果父亲存在且为红色while (parent && parent->_col == RED){Node* grandparent = parent->_parent;//情况1:cur为红色,p和u都为红色,g为黑色,这里的u是存在的//解决方法:p和n都变黑,g变红,在把cur当做g继续调整if (parent == grandparent->_left){Node* uncle = grandparent->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;//更新parentparent = cur->_parent;}else//情况2+3  uncle存在且为黑色或者uncle不存在{if (cur == parent->_left){//情况2//解决方法:右单旋,将p变黑,g变红RotateR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}else//情况3:双旋转{RotateL(parent);RotateR(grandparent);grandparent->_col = RED;cur->_col = BLACK;//双旋转后cur变为了根}//这里类比根节点为色,不需要在调整了break;}}else//grandparent->right == parent{//这里也是和上面一样分为三种情况Node* grandparent = parent->_parent;Node* uncle = grandparent->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;//更新parentparent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);//左单旋转parent->_col = BLACK;grandparent->_col = RED;}else{RotateR(parent);RotateL(grandparent);grandparent->_col = RED;cur->_col = BLACK;//双旋转后cur变为了根}break;}}}//调整完成,把根节点变黑_root->_col = BLACK;return true;}//右单旋void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;Node* grandparent = parent->_parent;//让subLR变为parent的左,parent->_left = subLR;//这里要判断一下subLR不为空if (subLR){subLR->_parent = parent;}//parent变为subL的右subL->_right = parent;parent->_parent = subL;//parent就是为根if (grandparent == nullptr){_root = subL;subL->_parent = grandparent;}else{//parnet是上grandparent的左子树if (grandparent->_left == parent){grandparent->_left = subL;}else{grandparent->_right = subL;}subL->_parent = grandparent;}}//左单旋void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;Node* ppNode = parent->_parent;parent->_right = subRL;if (subRL){subRL->_parent = parent;}subR->_left = parent;parent->_parent = subR;//parnet为根,要更新根if (ppNode == nullptr){_root = subR;subR->_parent = ppNode;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}}void Inorder(){_Inorder(_root);}void _Inorder(Node* root){if (root == nullptr)return;_Inorder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_Inorder(root->_right);}bool Check(Node* root, int blackNum, const int ref){if (root == nullptr){//已经递归到最深处进行,本路径的黑节点树和ref数量对比if (blackNum != ref){cout << "违反规则:本条路径的黑色节点的数量跟最左路径不相等" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){cout << "违反规则:出现连续红色节点" << endl;return false;}if (root->_col == BLACK){++blackNum;}return Check(root->_left, blackNum, ref)&& Check(root->_right, blackNum, ref);}bool IsBalance(){if (_root == nullptr){return true;}if (_root->_col != BLACK){return false;}//求出最左路节点有多少个黑节点int ref = 0;Node* left = _root;while (left){if (left->_col == BLACK){++ref;}left = left->_left;}return Check(_root, 0, ref);}
private:Node* _root = nullptr;};void TestRBTree1()
{//int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };RBTreeh<int, int> t;for (auto e : a){/*if (e == 18){int x = 0;}*/t.insert(make_pair(e, e));cout << "insert" << e << ":" << t.IsBalance() << endl;}t.Inorder();cout << t.IsBalance() << endl;
}//void TestRBTree2()
//{
//	srand(time(0));
//	const size_t N = 100000;
//	RBTreeh<int, int> t;
//	for (size_t i = 0; i < N; ++i)
//	{
//		size_t x = rand();
//		t.insert(make_pair(x, x));
//		//cout << t.IsBalance() << endl;
//	}
//
//	//t.Inorder();
//	cout << t.IsBalance() << endl;
//}

四、AVL树和红黑树的比较 

AVL树(Adelson-Velsky and Landis tree)和红黑树都是自平衡的二叉搜索树,它们在维持树的平衡性上采用了不同的策略。以下是它们之间的一些比较:

  1. 平衡性维护策略:

    • AVL树: 通过保持任意节点的左右子树的高度差(平衡因子)不超过1来维护平衡。在每次插入或删除操作后,可能需要旋转来恢复平衡。
    • 红黑树: 通过引入额外的颜色信息和一些规则,确保树的高度保持在较小的范围内。具体来说,红黑树的平衡性维护是通过节点的颜色和一些颜色约束来实现的。
  2. 平衡因子和颜色信息:

    • AVL树: 使用平衡因子(Balance Factor)来表示每个节点左右子树的高度差。通常,平衡因子为 -1、0、1。
    • 红黑树: 使用颜色信息(红色或黑色)来表示树的平衡状态。通过遵循红黑树的性质,确保了树的平衡。
  3. 旋转操作:

    • AVL树: 插入或删除可能需要执行多次旋转操作,包括左旋、右旋、左右旋、右左旋等。
    • 红黑树: 插入或删除通常只需要执行一到两次旋转操作,因为红黑树引入了颜色信息,更灵活地维持平衡。
  4. 性能影响:

    • AVL树: 由于 AVL 树对平衡的要求更为严格,因此在插入和删除等操作时可能会导致更多的旋转,相对来说更耗费性能。
    • 红黑树: 由于其相对宽松的平衡条件,红黑树在插入和删除等操作时通常执行的旋转较少,因此性能可能相对更好。
  5. 应用场景:

    • AVL树: 适用于对搜索性能有较高要求的场景,例如在数据库中需要快速检索数据。
    • 红黑树: 通常在需要高效的插入和删除操作的情况下使用,例如在集合类的实现中。

总体而言,选择 AVL 树还是红黑树取决于应用的特定需求。如果搜索操作远远超过插入和删除,可能更倾向于使用 AVL 树。而在插入和删除操作频繁的情况下,红黑树可能更为适用。

相关文章:

[数据结构]-红黑树

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、红黑树的…...

Android 13.0 Launcher3 app列表页桌面图标按安装时间排序

1.概述 在13.0的系统rom定制化开发中,在对Launcher3进行功能开发时,系统默认的app列表页排序是安装app名称进行排序的, 由于功能的需要要求按照app安装时间进行排序,这就需要找到相关的排序地方,进行排序方式的修改就能完成这个功能 2.Launcher3 app列表页桌面图标按安装…...

QFont如何设置斜体|QlineEdit设置只能输入数字|QThread::finished信号发出后worker未调用析构函数

QFont如何设置斜体 要设置 QFont 的斜体,你可以使用 setItalic() 方法。以下是一个示例代码: #include <QApplication> #include <QLabel> #include <QFont> int main(int argc, char *argv...

中伟视界:创新解决方案,搭建自适应的AI算法模型训练平台

搭建AI算法模型自训练平台是当今人工智能领域的热门话题&#xff0c;但是其中存在着许多技术难点需要克服。 自训练平台需要具备高效的算法模型&#xff0c;这就要求能够处理庞大的数据量并进行高速计算。 平台需要具备强大的数据管理及存储能力&#xff0c;以满足训练过程中的…...

UML建模图文详解教程08——部署图

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl本文参考资料&#xff1a;《UML面向对象分析、建模与设计&#xff08;第2版&#xff09;》吕云翔&#xff0c;赵天宇 著 部署图概述 部署图(deployment diagram)也被译作配置…...

发布鸿蒙的第一个java应用

1.下载和安装华为自己的app开发软件DevEco Studio HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 2.打开IDE新建工程&#xff08;当前用的IDEA 3.1.1 Release&#xff09; 选择第一个&#xff0c;其他的默认只能用(API9)版本&#xff0c;搞了半天才发现8&#xff…...

【C++干货铺】优先队列 | 仿函数

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 优先队列&#xff08;priority_queue &#xff09;的介绍和使用 priority_queue的介绍 priority_queue的使用 大堆 小堆 priority_queue的模拟实现 仿…...

突破技术障碍:软件工程师如何应对项目中的难题?

在软件开发项目中&#xff0c;工程师常常会遇到各种技术难题。这些难题可能涉及到复杂的算法、不兼容的系统、难以预见的软件行为&#xff0c;或者其他许多方面。 以下是一些策略和方法&#xff0c;可以帮助软件工程师有效地应对这些挑战&#xff1a; 1、理解问题&#xff1a;…...

Linux(7):Vim 程序编辑器

vi 基本上 vi 共分为三种模式&#xff0c;分别是【一般指令模式】、【编辑模式】与【指令列命令模式】。 这三种模式的作用分别是&#xff1a; 一般指令模式(command mode) 以 vi 打开一个文件就直接进入一般指令模式了(这是默认的模式&#xff0c;也简称为一般模式)。在这个模…...

windows搭建gitlab教程

1.安装gitlab 说明&#xff1a;由于公司都是windows服务器&#xff0c;这里安装以windows为例&#xff0c;先安装一个虚拟机&#xff0c;然后安装一个docker&#xff08;前提条件&#xff09; 1.1搜索镜像 docker search gitlab #搜索所有的docker search gitlab-ce-zh #搜索…...

力扣:单调栈算法思路题

单调栈分为单调递增栈和单调递减栈&#xff0c;通过使用单调栈我们可以访问到最近一个比它大&#xff08;小&#xff09;的元素。 &#x1f34a; 单调递增栈&#xff1a;单调递增栈就是从栈底到栈顶数据是依次递增&#xff0c;通常是寻找某方向第一个比它小的元素。 &#x1f…...

11 月 25 日 ROS 学习笔记——3D 建模与仿真

文章目录 前言一、在 ROS 中自定义机器人的3D模型1. 在 rviz 里查看3D模型2. xacro 二、Gazebo1. urdf 集成 gazebo2. 综合应用1). 运动控制及里程计2). 雷达仿真3). 摄像头信息仿真4). kinect 深度相机仿真5). 点云 前言 本文为11 月 25 日 ROS 学习笔记——3D 建模与仿真&am…...

MidJourney笔记(3)-Prompts

MidJourney的Prompts介绍 MidJourney的Prompts是MidJourney的核心之一,这也是我们后续使用MidJourney过程中最重要的工作内容,根据生成的图片,不断的优化我们的Prompts内容。 那Prompts的中文意思是提示的意思。 Prompts的提示语有很多,最基础的用法就是: /imagine prompt…...

贪心 D. Least Cost Bracket Sequence

Problem - D - Codeforces 题目大意&#xff1a;给一个只包含(&#xff0c;)&#xff0c;?三个字符的字符串。每个?可以转为(或者)&#xff0c;对于第 i i i个?转为(需要花费 a i a_i ai​&#xff0c;转为)需要花费 b i b_i bi​。现在问能否让该字符串转为合法的括号匹配…...

iOS APP包分析工具 | 京东云技术团队

介绍 分享一款用于分析iOSipa包的脚本工具&#xff0c;使用此工具可以自动扫描发现可修复的包体积问题&#xff0c;同时可以生成包体积数据用于查看。这块工具我们团队内部已经使用很长一段时间&#xff0c;希望可以帮助到更多的开发同学更加效率的优化包体积问题。 工具下载…...

在 VSCode 中使用 GDB 进行 C/C++ 程序调试(图文版)

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…...

任意文件读取漏洞理解

任意文件读取漏洞理解 1. 漏洞描述&#xff1a; 任意文件读取漏洞是指攻击者可以利用漏洞读取系统上的任意文件&#xff0c;包括敏感信息的配置文件、用户数据甚至系统文件&#xff0c;从而获取未经授权的访问权限。 2. 漏洞原理&#xff1a; 这种漏洞通常是由程序处理用户输入…...

linux 安装yum

问题1&#xff1a;File "/usr/libexec/urlgrabber-ext-down", line 28 except OSError, e: ^ 问题2&#xff1a;yum File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ vim /usr/…...

数学启发式

学习资料&#xff1a; 优化求解器 | Gurobi 数学启发式算法&#xff1a;参数类型与案例实现 数学启发式算法 | 可行性泵 (Feasibility Pump)算法精讲&#xff1a;一份让您满意的【理论介绍编程实现数值实验】学习笔记(PythonGurobi实现) 大佬到底是大佬&#xff01;这些资料太…...

Win10/Win11 使用Wsl的Ubuntu 子系统搭建CGO环境,相当于Ubuntu下开发。GO环境CGO搭建,支持交叉编译

背景&#xff1a; 之前是使用Mac 开发&#xff0c;最近切换到win11下面。发现使用cgo编译有问题。 下面记载了我的使用方法。 环境&#xff1a; win11&#xff08;win10理论一样&#xff09; win11 安装了wsl2的环境&#xff0c;并且安装了ubuntu系统。 在win11 上面安装了g…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...