红黑树的插入与删除

news2024/11/15 15:57:07

文章目录

  • 红黑树概念
    • 红黑树的`性质`:
  • 红黑树的插入操作
    • 情况一
    • 情况二
    • 情况三
  • 小总结
  • 红黑树的验证
  • 红黑树的删除
    • 一.删除单孩子节点
      • 1. 删除节点颜色为黑色
      • 2. 删除颜色为红色
    • 二. 删除叶子节点
      • 1. 删除节点为红色
      • 2.删除节点为黑色
        • 2.1兄弟节点为黑色,有孩子节点,并且孩子节点再兄弟节点的同一侧
        • 2.2. 兄弟节点为黑色,有孩子节点,并且孩子节点再兄弟节点的另一侧
        • 2.3 兄弟节点为黑色,无孩子节点或者孩子节点都为黑色。
        • 2.4 兄弟节点为红色
  • 代码实现:

红黑树概念

先来回顾一下AVL树:在我们讲解AVL树的时候,我们会设置一个平衡因子来控制我们树的高度,通过右子树-左子树这种方式来表示我们平衡因子的大小,如果bf绝对值大于·1,那就说明不平衡,此时需要旋转处理从而让树达到平衡。(绝对平衡

而红黑树是设置一个颜色并通过一些性质来是红黑树达到近似平衡。(每个节点不是红色的就是黑色的)

红黑树的性质

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

这里对第三点做个解释:不能存在连续的红色节点。同时有了上面的性质限制,我们就可以保证二叉树最长路径不超过最短路径的两倍。(为什么呢?)

在这里插入图片描述

红黑树中我们可以吧每一个空节点代表为一条路径,所以上图我们一共就有11条路径,那么每一条路径中我们黑色节点的数量都为两个虽然空节点代表黑色,这里不加入计算)那么最短路径就是全为黑色节点的路径最长路径就是一黑一红交错的路径。所以由于我们第四条性质限定了我们每条路径的黑色节点数量必须相同,所以才会有最长路径不超过最短路径的两倍这样一个结论。

  • 为了方便以后实现map和set的封装,代买实现都是添加了一个头节点。

红黑树的插入操作

在了解插入操作的时候,我们要明确新增的节点一定为红色

由于根节点一定为黑色,又要保证第四条性质的黑数同,所以当我们新增的节点一定为黑色。

在这里插入图片描述

同时为了方便描述,我们把新增节点命名为:c(cur),新增节点的父节点为p(parent),父节点的兄弟节点命名为:u(uncle)g(grandfather):爷爷节点

情况一

当我们了解了上面的知识过后,我们来分析一下:我们左边插入和右边插入都没有问题。

看下面的情况:

如果我们这样插入呢?由于性质三规定了不能存在连续的红色节点,所以此时我们需要调整,那如何调整呢?

情况一:c为新增,u为红,p为红,g为黑(也只能是黑色,不可能有连续的红色节点)

解决方案:此时我们只需要让u和p变黑,然后g变红,把g赋值给c,继续向上调整。

我们先来看一个简单的栗子:

上图是我们g节点为根的情况,还有可能为一棵树的子树,所以我们还需要继续向上调整。如图:

在这里插入图片描述

情况二

c为新增,u存在且为黑/u不存在,p为红,g为黑

在这里插入图片描述

解决方法:旋转完之后,只需要让g变红色,p变为黑色即可。同时我们的情况二是由情况一变过来的。

在这里插入图片描述

情况三

c为新增但是p的另一侧,u存在且为黑/u不存在,p为红,g为黑

解决方法:双旋完之后,让g变为红色,c变为黑色。双旋逻辑和AVL树一样,只不过这里我们并不需要维护平衡因子了。

小总结

插入过程种,当我们c为红色,p为红色的时候违反了性质三,所以我们需要进行处理,所以处理的结束条件就是当我们p为黑色的时候就不需要处理了。情况二和情况三旋转完之后已经不需要处理了。

原因:

旋转的时候g有两种情况:1.根 2. 子树

  1. 作为根的话,旋转完毕就结束了

  2. 作为子树,它的父节点一定为黑色节点,所以当我们旋转完之后把c变为g的位置的时候,p的指向为黑色节点,所以也不需要继续调整了。

由于我们新增节点必须为红色,旋转的条件是一黑一红,而且旋转只能由情况一转化为情况二才进行旋转,那么既然有红色节点那么g肯定为黑色,那么g->_parent节点也一定为黑色,如果g->_parent是红色的话,那我们不就相当于新增了一个黑色节点了吗,这样是不行的。所以旋转完之后没有必要继续调整。

代码实现:

bool insert(const K& key)
		{
		//只有一个头节点
		if (pHead->_parent == pHead)
		{
			pHead->_parent = new Node(key);
			pHead->_parent->_parent = pHead;
			pHead->_parent->_col = BLACK;
			return true;
		}
		Node* cur = pHead->_parent;
		Node* parent = cur->_parent;
		while (cur)
		{
			if (key < cur->_data)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (key > cur->_data)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
				return false;
		}
		cur = new Node(key);
		cur->_parent = parent;
		//连接新增节点与父节点的关系
		if (parent->_data > key)
			parent->_left = cur;
		else
			parent->_right = cur;

		Node* grandfather = parent->_parent;
		Node* uncle = nullptr;
		//满足parent的颜色是红色节点 并且 parent不是哨兵节点。
		while (parent->_col == RED && parent != pHead)
		{
			if (grandfather->_left == parent)
				uncle = grandfather->_right;
			else
				uncle = grandfather->_left;

			if (uncle && uncle->_col == RED) //p红色,u红色
			{
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;
				cur = grandfather;
				parent = grandfather->_parent;
				grandfather = parent->_parent;
			}
			else if ((uncle && uncle->_col == BLACK) || uncle == nullptr)
			{
				//右单旋
				if (grandfather->_left == parent && parent->_left == cur)
				{
					RotateR(grandfather);
					grandfather->_col = RED;
					parent->_col = BLACK;
				}
				else if (grandfather->_right == parent && parent->_right == cur)
				{
					//左单旋
					RotateL(grandfather);
					grandfather->_col = RED;
					parent->_col = BLACK;
				}
				else if (grandfather->_left == parent && parent->_right == cur)
				{
					//左右双旋
					RotateL(parent);
					RotateR(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}
				else if (grandfather->_right == parent && parent->_left == cur)
				{
					//右左双旋
					RotateR(parent);
					RotateL(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}
				break;
			}
			else
			{
				assert(false);
			}
		}
		pHead->_parent->_col = BLACK;
		return true;
	}

红黑树的验证

我们只需要根据性质进行验证即可:

  1. 根节点为黑色
  2. 不能存在连续的红色节点
  3. 每条路径中黑色数量相同

那如何求每一条路径的黑色节点数量呢?每次遍历到空节点其实就是一条路径完全走完了。

代码实现:

    bool IsRBTree()
            {
                return _isRBTree(pHead->_parent);
            }	
int Height()
	{
		return TreeHigh(pHead->_parent);
	}
private:

	int TreeHigh(Node* root)
	{
		if (root == nullptr || root->_parent == root)
			return 0;
		return max(TreeHigh(root->_left),TreeHigh(root->_right)) + 1;
	}

	bool _isRBTree(Node* root)
	{
		//只有一个头节点
		if (root->_parent == root)
			return true;
		Node* LeftMost = root;
		if (root->_col != BLACK)
		{
			cout << " 违反性质二:根节点为黑色 " << endl;
			return false;
		}
		int k = 0;
		while (LeftMost)
		{
			if (LeftMost->_col == BLACK)
				k++;
			LeftMost = LeftMost->_left;
		}
		return IsSameBlack(root->_left,1,k) && IsSameBlack(root->_right, 1, k);
	}

	bool IsSameBlack(Node* root, size_t cnt, int k)
	{
		if (root == nullptr)
		{
			cout << "当前路径黑色节点数量:" << cnt << endl;
			if (cnt != k)
			{
				cout << "违反性质四:每条路径中的黑色节点数量不一样 " << endl;
				return false;
			}
			return true;
		}
		if (root->_col == BLACK)
			cnt++;
		Node* parent = root->_parent;
		if (parent != pHead && parent->_col == RED && root->_col == RED)
		{
			cout << " 违反性质三:不能有连续的红色节点" << endl;
			return false;
		}
		return IsSameBlack(root->_left, cnt, k) && 
		IsSameBlack(root->_right, cnt, k);
	}

红黑树的删除

红黑树的删除和二叉搜索树的删除类似都有三种情况:

  1. 删除叶子节点
  2. 删除单孩子节点
  3. 删除双孩子节点

我们先来回忆以下双孩子节点如何删除,我们需要去找一个替换节点来替换此时的删除节点,那么这个替换节点需要满足:

  1. 比要删除的左子树大
  2. 比要删除的右子树小

所以我们有两种选择:1. 左子树的最大节点 2. 右子树的最小节点。接下来我实现的都是找右子树的最小节点。

那么当我们找到这个可替换节点的时候无非就是两种情况: 1. 可替换节点为叶子节点 2. 可替换节点为单孩子节点。

那么其实我们删除两个孩子节点的操作当我们把可替换节点的值赋值给要删除节点的时候,其实就变为了删除叶子节点或者删除单孩子节点。

有了上面的理解,我们可以值需要梳理删除叶子节点和删除单孩子节点的思路即可。

这里我们先来说删除单孩子节点。

一.删除单孩子节点

这里分为两种情况:

  1. 删除节点颜色为黑色
  2. 删除节点为红色

1. 删除节点颜色为黑色

此时我们那个孩子节点的颜色只有一种情况,那就是红色节点,那么由于我们删除过后会少一个黑色节点,所以当我们连接新的节点过后,要把这个红色节点变为黑色。

2. 删除颜色为红色

那它的孩子节点一定为黑色,直接连接孩子节点与父节点的关系,然后直接删除即可。

二. 删除叶子节点

1. 删除节点为红色

直接删除即可,然后需要把父节点对应的左右孩子置空,不然后面会访问野指针(O.0!)

2.删除节点为黑色

如上图,如果我们把节点6删除过后,那最左边的路径黑色节点就会少一个,这样就违反了第四条性质。这时候我们就要分类讨论它的兄弟节点的颜色了。

2.1兄弟节点为黑色,有孩子节点,并且孩子节点再兄弟节点的同一侧

这里我们都以s称为兄弟节点,sr就是兄弟节点的右子树。

在这里插入图片描述

如上图,进行单选的时候我们需要把颜色依次赋值:sr->_col = s->_cols->_col = p->_colp->_col = BLACK

同理进行右单旋也是如此,这里就不再赘述了。

2.2. 兄弟节点为黑色,有孩子节点,并且孩子节点再兄弟节点的另一侧

这个时候就是双旋了。

在这里插入图片描述

双旋唯一不一样的就是颜色的变换,这个时候我们直接让 sl->_col = p->_colp->_col = BLACK,这时候直接让兄弟节点的孩子节点复制父亲节点的颜色,然后父亲节点变黑,最后进行双旋操作即可。

2.3 兄弟节点为黑色,无孩子节点或者孩子节点都为黑色。

这个时候需要先把兄弟节点变红,然后再观察现在的parent(父亲节点):

  1. 如果父亲节点为红色或者为根,直接让父亲节点变为黑色,最后删除节点即可。
  2. 如果父亲节点为黑色并且不是根节点的话,就要继续观察,然后重复我们删除节点为黑色的这个操作

在这里插入图片描述

2.4 兄弟节点为红色

此时直接交换兄弟节点与父亲节点的颜色,然后对p(父亲节点)进行向着删除节点的方向进行旋转,如果删除节点再p左侧就进行左旋,如果删除节点再p右侧就进行右旋。然后继续观察当前的删除节点,继续重复删除节点为黑色的操作

在这里插入图片描述

代码实现:

//进来的都是叶子节点为黑色的情况,那么如果叶子节点为黑色的话,一定有兄弟节点。不然违反了性质4.
void ChangeColor(Node* cur, Node* parent)
{
	Node* uncle = nullptr;
	//1. 如果uncle是黑色节点,并且它有红色的孩子节点(旋转的状态)
	//2. 如果uncle是黑色节点,并且他的孩子都是黑色节点(NULL也算),那么就把兄弟节点变为红色同时向上遍历双重黑色节点
	//3. 如果uncle是红色节点,交换兄弟和parent的颜色,然后向删除节点的方向旋转,然后继续观察兄弟节点
	while (parent != pHead)
	{
		if (parent->_left == cur)
		{
			uncle = parent->_right;
		}
		else
		{
			uncle = parent->_left;
		}

		if (uncle->_col == BLACK)
		{
			//进行右单旋
			if (parent->_left == uncle && uncle->_left && uncle->_left->_col == RED)
			{
				Node* uncle_left = uncle->_left;
				//变色
				uncle_left->_col = uncle->_col;
				uncle->_col = parent->_col;
				parent->_col = BLACK;
				//旋转
				RotateR(parent);
				break;
			}
			else if (parent->_right == uncle && uncle->_right && uncle->_right->_col == RED)
			{
				//进行左单旋
				Node* uncle_right = uncle->_right;
				//变色
				uncle_right->_col = uncle->_col;
				uncle->_col = parent->_col;
				parent->_col = BLACK;
				RotateL(parent);
				break;
			}
			else if (parent->_left == uncle && uncle->_right && uncle->_right->_col == RED)
			{
				//进行左右双旋
				Node* uncle_right = uncle->_right;
				//变色
				uncle_right->_col = parent->_col;
				parent->_col = BLACK;
				RotateL(uncle);
				RotateR(parent);
				break;
			}
			else if (parent->_right == uncle && uncle->_left && uncle->_left->_col == RED)
			{
				//进行右左双旋
				Node* uncle_left = uncle->_left;
				//变色
				uncle_left->_col = parent->_col;
				parent->_col = BLACK;
				RotateR(uncle);
				RotateL(parent);
				break;
			}
			else if ((uncle->_left == nullptr && uncle->_right == nullptr) || (uncle->_left && uncle->_right && uncle->_left->_col == BLACK && uncle->_right->_col == BLACK))
			{
				//兄弟节点的孩子全为黑色节点
				//把兄弟节点变为红色,然后双重黑色节点往上调继续遍历
				uncle->_col = RED;
				//遍历到根节点或者红色节点把节点变为黑色退出即可。
				if ((uncle->_parent != pHead->_parent && uncle->_parent->_col == RED) || (uncle->_parent == pHead->_parent))
				{
					uncle->_parent->_col = BLACK;
					break;
				}
				else
				{
					cur = uncle->_parent;
					parent = cur->_parent;
				}
			}

		}
		else if (uncle->_col == RED)
		{
			//交换uncle和parent的颜色,Parent变为黑色,然后向删除节点方向旋转,再看双重黑节点

			uncle->_col = parent->_col;
			parent->_col = RED;
			if (parent->_left == cur)
			{
				RotateL(parent);
			}
			else
			{
				RotateR(parent);
			}
			cur = cur;
			parent = cur->_parent;
		}

	}



}

bool erase(const K& key)
{
	//只有一个哨兵节点无法删除。
	if (pHead->_parent == pHead)
		return false;
	Node* cur = pHead->_parent;
	Node* parent = pHead;
	while (cur)
	{
		if (key < cur->_data)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (key > cur->_data)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			//叶子节点
			if (cur->_left == nullptr && cur->_right == nullptr)
			{
				//如果删除的是根节点,直接让哨兵的parent指针指向自己。
				if (parent == pHead)
				{
					pHead->_parent = pHead;
					delete cur;
					return true;
				}
				else if (cur->_col == RED)//红色的话直接删除
				{
					if (parent->_left == cur)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
					delete cur;
					return true;
				}
				else if (cur->_col == BLACK) //如果删除的节点为黑色节点
				{
					ChangeColor(cur,parent);
					if (parent->_left == cur)
						parent->_left = nullptr;
					else
						parent->_right = nullptr;
					delete cur;

					return true;
				}
			}
			else if (cur->_left == nullptr) //左边为空
			{
				//删除的为根节点,直接改变pHead的指向即可。
				if (parent == pHead)
				{
					pHead->_parent = cur->_right;
					if (cur->_right)
					{
						cur->_right->_col = BLACK;
						cur->_right->_parent = pHead;
					}
					delete cur;
					return true;
				}
				else if (cur->_col == BLACK)
				{
					//判断为父亲节点的哪一边
					if (parent->_left == cur)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
					//如果删除的单孩子节点为黑色,就需要把删除节点的右孩子变为黑色。如果有右孩子的话)
					if (cur->_right)
					{
						cur->_right->_col = BLACK;
						cur->_right->_parent = parent; //如果有的话别忘了连接父节点
					}
					delete cur;
					return true;
				}
				else if (cur->_col == RED)
				{
					//判断为父亲节点的哪一边
					if (parent->_left == cur)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
					//如果删除的单孩子节点为红色,直接删除
					delete cur;
					return true;
				}
			}
			else if (cur->_right == nullptr)
			{
				//删除的为根节点,直接改变pHead的指向即可。
				if (parent == pHead)
				{
					pHead->_parent = cur->_left;
					if (cur->_left)
					{
						cur->_left->_col = BLACK;
						cur->_left->_parent = pHead;
					}
					delete cur;
					cur = nullptr;
					return true;
				}
				else if (cur->_col == BLACK)
				{
					//判断为父亲节点的哪一边
					if (parent->_left == cur)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;
					}
					//如果删除的单孩子节点为黑色,就需要把删除节点的左孩子变为黑色(如果有左孩子的话)
					if (cur->_left)
					{
						cur->_left->_col = BLACK;
						cur->_left->_parent = parent;

					}
					delete cur;
					cur = nullptr;
					return true;
				}
				else if (cur->_col == RED)
				{
					//判断为父亲节点的哪一边
					if (parent->_left == cur)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;
					}
					//如果删除的单孩子节点为红色,直接删除
					delete cur;
					cur = nullptr;
					return true;
				}
			}
			else //双孩子节点
			{
				//如果删除节点为红色
				if (cur->_col == RED)
				{
					Node* RightMinP = cur;
					Node* RightMin = cur->_right;
					while (RightMin && RightMin->_left)
					{
						RightMinP = RightMin;
						RightMin = RightMin->_left;
					}
					cur->_data = RightMin->_data;
					//如果RightMin的颜色为黑色
					if (RightMin->_col == BLACK)
					{
						//如果RightMin有右孩子,那么一定为红色的,删除RightMin之后要把他的右孩子变为黑色。

						if (RightMin->_right)
						{
							RightMin->_right->_col = BLACK;
							RightMin->_right->_parent = RightMinP;

							// 如果有红色节点的uha,直接连接并且赋值为黑色
							if (RightMinP->_left == RightMin)
							{
								RightMinP->_left = RightMin->_right;
							}
							else
							{
								RightMinP->_right = RightMin->_right;
							}
							delete RightMin;
						}
						
					
						
						else //如果没有的话那么转化为删除黑色叶子节点
						{
							ChangeColor(RightMin, RightMinP);
							if (RightMinP->_left == RightMin)
							{
								RightMinP->_left = nullptr;
							}
							else
							{
								RightMinP->_right = nullptr;
							}
							delete RightMin;
						}
					
						return true;
					}
					else//如果RightMin的颜色为红色,直接删除,连接右孩子
					{
						if (RightMinP->_left == RightMin)
						{
							RightMinP->_left = RightMin->_right;
						}
						else
						{
							RightMinP->_right = RightMin->_right;
						}

						if (RightMin->_right)
						{
							RightMin->_right->_parent = RightMinP;
						}
						delete RightMin;
						return true;
					}
				
				}
				else//如果删除节点为黑色
				{
					Node* RightMinP = cur;
					Node* RightMin = cur->_right;
					while (RightMin && RightMin->_left)
					{
						RightMinP = RightMin;
						RightMin = RightMin->_left;
					}
					cur->_data = RightMin->_data;
					//如果RightMin的颜色为黑色
					if (RightMin->_col == BLACK)
					{

						if (RightMin->_right)
						{
							//如果RightMin有右孩子,那么一定为红色的,删除RightMin之后要把他的右孩子变为黑色。

							RightMin->_right->_col = BLACK;
							RightMin->_right->_parent = RightMinP;

							if (RightMinP->_left == RightMin)
							{
								RightMinP->_left = RightMin->_right;
							}
							else
							{
								RightMinP->_right = RightMin->_right;
							}
							delete RightMin;
							return true;
						}
						
						else //如果没有的话那么转化为删除黑色叶子节点
						{
							ChangeColor(RightMin, RightMinP);
							if (RightMinP->_left == RightMin)
							{
								RightMinP->_left = nullptr;
							}
							else
							{
								RightMinP->_right = nullptr;
							}
							delete RightMin;
						}
						return true;
					}
					else//如果RightMin的颜色为红色,直接删除,连接右孩子
					{
						if (RightMinP->_left == RightMin)
						{
							RightMinP->_left = RightMin->_right;
						}
						else
						{
							RightMinP->_right = RightMin->_right;
						}
						if (RightMin->_right)
						{
							RightMin->_right->_parent = RightMinP;
						}
						delete RightMin;

						return true;
					}
				}
			}
		}
	}
	return false;
}

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

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

相关文章

window下redis的安装

下载地址&#xff1a;https://github.com/tporadowski/redis/releases Windows下的.msi安装和.zip格式区别&#xff1a; .msi是Windows installer开发出来的程序安装文件&#xff0c;它可以让你安装&#xff0c;修改&#xff0c;卸载你所安装的程序。说白了.msi就是Windows in…

KeyFreeze 1.0.1.0 临时禁用电脑鼠标和键盘

KeyFreeze 是一个免费实用的临时禁用电脑鼠标和键盘的软件&#xff1b;软件支持 Windows 。 它完全免费&#xff0c;体积非常小巧&#xff0c;使用场景是当你在某些时候需要临时禁用鼠标和键盘&#xff0c;让鼠标和键盘无法使用&#xff0c;防止误触。 开软件只有一个按钮&am…

stm32入门-----硬件SPI读写W25Q64

目录 前言 一、相关库函数介绍 1.初始化 2.写入数据 3.接收数据 4.获取标志位 二、软件SPI读写W25Q64 前言 上一期我们学习了stm32的SPI外设&#xff08;上一期链接&#xff1a;stm32入门-----硬件SPI外设-CSDN博客&#xff09;&#xff0c;那么我们本期就来…

最近很火的FLUX.1文生图模型本地一键整合包SwarmUI,schnell量化版,6G显存可畅玩的FLUX.1

最近一个新的文生图模型突然火出圈&#xff0c;它就是由Black Forest Labs&#xff08;黑森林实验室&#xff09;团队开发的FLUX.1。 Black Forest Labs估计很多人都没听说过&#xff0c;还以为是新生的创业团队&#xff0c;现在就先来说一说Black Forest Labs。玩过AI绘画的&a…

【Ansible 学习之旅】Ansible 介绍和架构

目录 Ansible 发展Ansible 介绍Ansible 组成 Ansible 发展 2012-03-09&#xff0c;发布0.0.1版 2015-10-17&#xff0c;Red Hat宣布1.5亿美元收购 官网&#xff1a;https://www.ansible.com/ 官方文档&#xff1a;https://docs.ansible.com/ Ansible 介绍 Ansible 可自动管理…

云存储技术:HBase HDFS 无感知迁移方案

在大数据生态系统中&#xff0c;HBase 和 HDFS 是两个关键组件。HBase 是一个分布式列式数据库&#xff0c;常用于实时读写大规模数据&#xff1b;HDFS 是一个高可靠的分布式文件系统&#xff0c;用于存储海量数据。 1、背景 随着业务的发展和技术的进步&#xff0c;可能需要对…

HDMI vs DP:LED显示屏背后的高清传输大揭秘

在如今数字化高速发展的时代&#xff0c;LED显示屏以其高亮度、高清晰度、长寿命等优点&#xff0c;广泛应用于广告、会议、娱乐等多个领域。然而&#xff0c;要让这些绚丽多彩的画面完美呈现&#xff0c;离不开背后默默工作的接口技术。今天&#xff0c;我们就来揭开LED显示屏…

前端react集成OIDC

文章目录 OpenID Connect (OIDC)3种 授权模式 【服务端】express 集成OIDC【前端】react 集成OIDCoidc-client-js库 原生集成react-oidc-context 库非组件获取user信息 OAuth 2.0 协议主要用于资源授权。 OpenID Connect (OIDC) https://openid.net/specs/openid-connect-core…

【安当产品应用案例100集】007-工业控制系统防勒索解决方案-安当RDM防勒索

《工业控制系统网络安全防护指南》是由工业和信息化部于2024年1月19日发布&#xff0c;旨在指导企业提升工业控制系统网络安全防护水平&#xff0c;确保新型工业化发展的安全根基。该指南适用于使用和运营工业控制系统的企业&#xff0c;包括但不限于可编程逻辑控制器&#xff…

【生成式人工智能-十-文字、图片、声音生成策略】

人工智能生成文字、图片、声音的方法 生成的本质生成的策略文字AR (Autoregressive Generation)图像和视频 NAR(Non-Autoregressive Generation)解决NAR生成品质低的问题 AR NAR 生成的本质 文字、图像、声音的生成的本质&#xff0c;就是给模型一个输入&#xff0c;模型把基…

大模型应用中的幻觉问题是什么?

大模型应用中的幻觉问题是什么&#xff1f; 在现代自然语言处理领域&#xff0c;大语言模型&#xff08;如GPT系列&#xff09;以其惊人的生成能力和语言理解能力被广泛应用。然而&#xff0c;随着这些模型的广泛使用&#xff0c;幻觉问题逐渐显现出其对实际应用的潜在影响。本…

怎样快速查询数家公司是否存在关联关系?

▶关联关系的查询是企业稳健运营和长期发展的关键环节 企业在关键时期需要查询数家公司是否存在关联关系&#xff0c;以确保合规性和透明度。这通常发生在年度审计、税务申报、并购活动、上市准备、风险评估和法律诉讼时。监管合规性检查、内部控制加强、市场策略制定、资金管…

加速区域市场扩张,ATFX任命Amer Zino为中东和北非业务发展总监

全球领先的差价合约经纪商ATFX再度向世界展示了其吸纳行业顶尖复合型人才的决心和能力。日前&#xff0c;ATFX旗下机构业务ATFX Connect宣布一项重磅人事任命&#xff0c;行业杰出领袖Amer Zino加入公司&#xff0c;出任中东和北非业务发展总监一职&#xff0c;并将常驻工作地阿…

【ARM】ULINK Pro如何和SWD接口进行连接调试

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决ULINK Pro和JTAR接口进行连接问题。 2、 问题场景 因为ULINK Pro本身自带的接口是Cortex-M ETM Interface 20-pin Connector。所以无法和JTAR接口直接进行连接。 图2-1 3、软硬件环境 1&#xff09;、软件版…

综合交易系统---强大的问财自定义实盘交易系统上线

这几天知识星球的朋友的需要&#xff0c;我重新写了问财自定义实盘交易系统&#xff0c;同时把数据库上线了&#xff0c;网页 https://gitee.com/li-xingguo11111/xg_data 调用网页的源代码数据服务器地址 http://124.220.32.224:8888/ 问财实盘设置&#xff0c;打开总结交易系…

【从零开始一步步学习VSOA开发】VSOA数据报

VSOA数据报 概念 Datagram 是 VSOA 的一种数据传输类型&#xff0c;通常这种类型用于传输一些不需要确认的数据&#xff0c;例如传输视频流数据或构建 VPN 网络。 Datagram 可以简单快速的在网络中传输数据。它即不需要建立连接&#xff0c;也不需要维护连接&#xff0c;因此…

GESP 一级 比赛

出错了 - 洛谷https://www.luogu.com.cn/contest/190441#problems 邀请码&#xff1a;zura 有讲解哦&#xff01;

SCAU学习笔记 - 高级语言程序设计课后习题

写在前面 趁着暑假赶紧把C语言的习题也补了 也欢迎看到这篇博客的小灯们来到华南农业大学喵 专栏里还有后续其他部分课程的学习笔记 如何提交自己的代码 首先给各位说一下这门课程的要求&#xff0c;首先是我们学校的校内OJ&#xff0c;我们计算机类专业的学生用的是前面这个…

突破 ES 引擎局限性在用户体验场景中的优化实践

回顾&#xff1a;ES 慢上游响应问题优化在用户体验场景中的实践-CSDN博客 上文介绍了用户体验管理平台&#xff08;简称 VoC&#xff09;在针对 ES 慢上游响应场景下的优化实践&#xff0c;本文继续介绍针对第二个痛点问题——ES 引擎局限性的性能优化实践进行介绍。 下文以搜…

MaxKB:基于 LLM大语言模型的知识库问答系统实操

1.MaxKB介绍 MaxKB 是一款基于 LLM&#xff08;Large Language Model&#xff09;大语言模型的知识库问答系统。MaxKB 的产品命名内涵为 “Max Knowledge Base”&#xff0c;为用户提供强大的学习能力和问答响应速度&#xff0c;致力于成为企业的最强大脑。与同类基于 LLM 的知…