【数据结构高阶】红黑树

目录

一、红黑树的概念

二、红黑树的性质

2.1 红黑树与AVL树的比较

三、红黑树的实现

3.1 红黑树节点的定义

3.2 数据的插入

3.2.1 红黑树的调整思路

3.2.1.1 cur为红,f为红,g为黑,u存在且为红

3.2.1.2 cur为红,f为红,g为黑,u不存在/u存在且为黑

3.2.1.2.1 g、f、cur构成一条直线

3.2.1.2.2 g、f、cur构成一条折线

3.2.2 调整部分的代码实现

3.3 红黑树的验证

3.4 测试代码

四、红黑树实现完整代码


一、红黑树的概念

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

二、红黑树的性质

● 每个结点不是红色就是黑色

● 根节点是黑色的

● 如果一个节点是红色的,则它的两个孩子结点是黑色的(不允许出现连续的红色节点)

● 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点(从根节点到每个叶子节点的空孩子路径上有相同数目的黑色节点)

● 每个叶子结点的空孩子节点都是黑色的

根据上述的五条性质,我们可以发现一个红黑树中如果有N个黑色节点,则根节点到任意一个叶子节点的距离:最短为㏒⑵N,最长为2㏒⑵N

2.1 红黑树与AVL树的比较

我们来看到下面的红黑树:

对于这棵红黑树,如果将其看成一个AVL树,是需要进行旋转的,但是在红黑树结构中却不需要

所以红黑树是近似平衡的,在搜索效率上会略逊AVL树一些,但是红黑树在结构上不要求绝对的平衡,这就造成插入相同的数据红黑树翻转的次数少于AVL树

实际使用中,在经常进行增删的场景下红黑树性能比AVL树更优,并且红黑树实现比较简单,所以实际运用中红黑树更多

三、红黑树的实现

3.1 红黑树节点的定义

enum Colour
{
	RED,
	BLACK
};

template<class Key, class Val>
struct RBTreeNode
{
	RBTreeNode<Key, Val>* _left;
	RBTreeNode<Key, Val>* _right;
	RBTreeNode<Key, Val>* _parent;//多一个指针指向其父节点,方便我们的后续操作
	pair<Key, Val> _kv;
	Colour _col;//颜色标识

	RBTreeNode(const pair<Key, Val>& kv)
		:_left(nullptr),
		_right(nullptr),
		_parent(nullptr),
		_kv(kv),
		_col(RED)//构造时,优先将节点的颜色置为红色
	{}
};

在这里提一下为什么要默认将节点的颜色置为红色:

在我们向红黑树中插入一个新节点时,如果将该节点置为黑色,就肯定会影响红黑树性质中的第四条:对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点

例如:

我们现在在上面这棵树中,不管在哪个叶子节点的下方插入一个黑色的新增节点,从根节点到插入的节点的空孩子的路径上的黑色节点数目会变为4,而从根节点到其他叶子节点的空孩子的路径上的黑色节点数目会都为3

所以我们将新增节点的颜色置为红色就一定不会违反第四条红黑树性质,但是第三条呢?如果插入节点的父节点是红色的怎么办?

怎么办我们后面再说,反正总归比置为黑色一定会违反第四条性质好吧

3.2 数据的插入

由于红黑树也是平衡二叉搜索树的一种,我们在插入数据时也要找到合适的位置进行插入:

template<class Key, class Val>
class RBTree
{
	typedef RBTreeNode<Key, Val> Node;
public:
	bool Insert(const pair<Key,Val>& kv)
	{
		Node* cur = _root, * parent = nullptr;
		while (cur)//找到合适的位置
		{
			if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				cout << "插入的值重复" << endl;
				return false;
			}
		}
		cur = new Node(kv);
		cur->_parent = parent;
		//将插入的节点连接上二叉树
		if (parent == nullptr)
		{
			_root = cur;
		}
		else if (kv.first < parent->_kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		return true;
	}

private:
	Node* _root = nullptr;
};

插入到合适的位置之后,我们还要检查是否破坏了红黑树的结构(由于我们插入的是红色节点,所以只会出现两个红色节点连续的情况),如果出现了该情况,我们就要对其进行分类讨论并解决:

3.2.1 红黑树的调整思路

下面我们将出现异常情况的两个节点的那个子节点叫做cur,cur的父节点叫做father(简称f),father的父节点叫做grandfather(简称g),father的兄弟节点叫做uncle(简称u)

例如:

接下来,我们分类讨论:

3.2.1.1 cur为红,f为红,g为黑,u存在且为红

下面画出的情况表示的是抽象出的情况:A、B、C、D、E都是满足构成红黑树的子树

对于这种情况我们先将f和u节点变黑,再将g节点变红即可:

调整完后,要记得再向上检查g节点的父节点是否为红色哦~(如果g节点为整棵红黑树的根,最后要将其颜色置为黑)

3.2.1.2 cur为红,f为红,g为黑,u不存在/u存在且为黑
3.2.1.2.1 g、f、cur构成一条直线

对于这种情况:若f为g的左孩子,cur为f的左孩子,则进行右单旋:

再将f变黑,g变红:

相反, f为g的右孩子,cur为f的右孩子,则进行左单旋转:

再将f变黑,g变红:

3.2.1.2.2 g、f、cur构成一条折线

f为g的左孩子,cur为f的右孩子,则做左右双旋,旋转完后将cur节点颜色置黑、g节点颜色置红:

相反, f为g的右孩子,cur为f的左孩子,则做右左双旋,旋转完后将cur节点颜色置黑、g节点颜色置红:

对于旋转操作还不熟悉的同学可以看到这里:【数据结构高阶】AVL树

3.2.2 调整部分的代码实现

template<class Key, class Val>
class RBTree
{
	typedef RBTreeNode<Key, Val> Node;
public:

	bool Insert(const pair<Key, Val>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
	}
	Node* cur = _root, * parent = nullptr;
	while (cur)//找到合适的位置
	{
		if (kv.first < cur->_kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (kv.first > cur->_kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			cout << "插入的值重复" << endl;
			return false;
		}
	}
	cur = new Node(kv);
	//将插入的节点连接上二叉树
	if (kv.first < parent->_kv.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
	//开始调整
	while (parent && parent->_col == RED)//红黑树的结构出现两个连续的红色节点
	{
		Node* grandfather = parent->_parent;
		if (parent == grandfather->_left)
		{
			Node* uncle = grandfather->_right;
			if (uncle && uncle->_col == RED)//cur为红,p为红,g为黑,u存在且为红
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandfather->_col = RED;
				//继续向上更新
				cur = grandfather;
				parent = cur->_parent;
			}
			elsecur为红,p为红,g为黑,u不存在/u存在且为黑
			{
				if (cur == parent->_left)//cur在p的左边,p也在g的左边,构成一条直线
				{
					//右单旋
					RotateR(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else//cur在p的右边,p在g的左边,构成一条折线
				{
					//左右双旋
					RotateL(parent);
					RotateR(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}
				break;//调整完跳出
			}
		}
		else
		{
			Node* uncle = grandfather->_left;
			if (uncle && uncle->_col == RED)//cur为红,p为红,g为黑,u存在且为红
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandfather->_col = RED;
				//继续向上更新
				cur = grandfather;
				parent = cur->_parent;
			}
			elsecur为红,p为红,g为黑,u不存在/u存在且为黑
			{
				if (cur == parent->_right)//cur在p的右边,p也在g的右边,构成一条直线
				{
					//左单旋
					RotateL(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else//cur在p的左边,p在g的右边,构成一条折线
				{
					//右左双旋
					RotateR(parent);
					RotateL(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}
				break;//调整完跳出
			}
		}
	}
	_root->_col = BLACK;//确保即便进行过调整后根节点颜色为黑
	return true;
}

private:
	void RotateL(Node* parent)//左单旋
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* pparent = parent->_parent;
		parent->_right = subRL;//更新parent的右节点
		if (subRL)//防止该节点为空
		{
			subRL->_parent = parent;//更新subRL的父节点
		}
		parent->_parent = subR;//更新parent的父节点
		subR->_left = parent;//subR的左子树置为parent
		subR->_parent = pparent;//更新subR的父节点
		if (pparent == nullptr)//旋转的是整棵树
		{
			_root = subR;//更新根节点
		}
		else//将旋转后的子树链接上整个二叉树
		{
			if (pparent->_left == parent)
			{
				pparent->_left = subR;
			}
			else
			{
				pparent->_right = subR;
			}
		}
	}

	void RotateR(Node* parent)//右单旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* pparent = parent->_parent;
		parent->_left = subLR;//更新parent的左节点
		if (subLR)//防止该节点为空
		{
			subLR->_parent = parent;//更新subLR的父节点
		}
		parent->_parent = subL;//更新parent的父节点
		subL->_right = parent;//subL的右子树置为parent
		subL->_parent = pparent;//更新subL的父节点
		if (pparent == nullptr)//旋转的是整棵树
		{
			_root = subL;//更新根节点
		}
		else//将旋转后的子树链接上整个二叉树
		{
			if (pparent->_left == parent)
			{
				pparent->_left = subL;
			}
			else
			{
				pparent->_right = subL;
			}
		}
	}

private:
	Node* _root = nullptr;
};

3.3 红黑树的验证

下面我们来写段代码来验证一课树是不是红黑树:

template<class Key, class Val>
class RBTree
{
	typedef RBTreeNode<Key, Val> Node;
public:

	bool IsBalance()
	{
		if (_root && _root->_col == RED)
		{
			cout << "根节点颜色是红色" << endl;
			return false;
		}

		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				++benchmark;
			cur = cur->_left;
		}

		// 连续红色节点
		return _Check(_root, 0, benchmark);
	}

private:
	bool _Check(Node* root, int blackNum, int benchmark)//计算每条路径上黑色节点的个数
	{
		if (root == nullptr)
		{
			if (benchmark != blackNum)
			{
				cout << "某条路径黑色节点的数量不相等" << endl;
				return false;
			}

			return true;
		}

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

		if (root->_col == RED
			&& root->_parent
			&& root->_parent->_col == RED)
		{
			cout << "存在连续的红色节点" << endl;
			return false;
		}

		return _Check(root->_left, blackNum, benchmark)
			&& _Check(root->_right, blackNum, benchmark);
	}

private:
	Node* _root = nullptr;
};

3.4 测试代码

void Test_RBTree()
{
	const size_t N = 50000;
	RBTree<int, int> t;
	for (size_t i = 0; i < N; ++i)
	{
		size_t x = rand() + i;
		t.Insert(make_pair(x, x));
	}
	t.InOrder();
	cout << t.IsBalance();
}

int main()
{
	Test_RBTree();
	return 0;
}

测试效果:

四、红黑树实现完整代码

#include<iostream>

using namespace std;

enum Colour
{
	RED,
	BLACK
};

template<class Key, class Val>
struct RBTreeNode
{
	RBTreeNode<Key, Val>* _left;
	RBTreeNode<Key, Val>* _right;
	RBTreeNode<Key, Val>* _parent;//多一个指针指向其父节点,方便我们的后续操作
	pair<Key, Val> _kv;
	Colour _col;//颜色标识

	RBTreeNode(const pair<Key, Val>& kv)
		:_left(nullptr),
		_right(nullptr),
		_parent(nullptr),
		_kv(kv),
		_col(RED)//默认构造时,优先将节点的颜色置为红色
	{}
};

template<class Key, class Val>
class RBTree
{
	typedef RBTreeNode<Key, Val> Node;
public:

	bool Insert(const pair<Key, Val>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
	}
	Node* cur = _root, * parent = nullptr;
	while (cur)//找到合适的位置
	{
		if (kv.first < cur->_kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (kv.first > cur->_kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			cout << "插入的值重复" << endl;
			return false;
		}
	}
	cur = new Node(kv);
	//将插入的节点连接上二叉树
	if (kv.first < parent->_kv.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
	//开始调整
	while (parent && parent->_col == RED)//红黑树的结构出现两个连续的红色节点
	{
		Node* grandfather = parent->_parent;
		if (parent == grandfather->_left)
		{
			Node* uncle = grandfather->_right;
			if (uncle && uncle->_col == RED)//cur为红,p为红,g为黑,u存在且为红
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandfather->_col = RED;
				//继续向上更新
				cur = grandfather;
				parent = cur->_parent;
			}
			elsecur为红,p为红,g为黑,u不存在/u存在且为黑
			{
				if (cur == parent->_left)//cur在p的左边,p也在g的左边,构成一条直线
				{
					//右单旋
					RotateR(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else//cur在p的右边,p在g的左边,构成一条折线
				{
					//左右双旋
					RotateL(parent);
					RotateR(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}
				break;//调整完跳出
			}
		}
		else
		{
			Node* uncle = grandfather->_left;
			if (uncle && uncle->_col == RED)//cur为红,p为红,g为黑,u存在且为红
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandfather->_col = RED;
				//继续向上更新
				cur = grandfather;
				parent = cur->_parent;
			}
			elsecur为红,p为红,g为黑,u不存在/u存在且为黑
			{
				if (cur == parent->_right)//cur在p的右边,p也在g的右边,构成一条直线
				{
					//左单旋
					RotateL(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else//cur在p的左边,p在g的右边,构成一条折线
				{
					//右左双旋
					RotateR(parent);
					RotateL(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}
				break;//调整完跳出
			}
		}
	}
	_root->_col = BLACK;//确保即便进行过调整后根节点颜色为黑
	return true;
}
	void InOrder()//中序遍历
	{
		_InOrder(_root);
		cout << endl;
	}

	bool IsBalance()
	{
		if (_root && _root->_col == RED)
		{
			cout << "根节点颜色是红色" << endl;
			return false;
		}

		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				++benchmark;
			cur = cur->_left;
		}

		// 连续红色节点
		return _Check(_root, 0, benchmark);
	}

private:
	void RotateL(Node* parent)//左单旋
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		Node* pparent = parent->_parent;
		parent->_right = subRL;//更新parent的右节点
		if (subRL)//防止该节点为空
		{
			subRL->_parent = parent;//更新subRL的父节点
		}
		parent->_parent = subR;//更新parent的父节点
		subR->_left = parent;//subR的左子树置为parent
		subR->_parent = pparent;//更新subR的父节点
		if (pparent == nullptr)//旋转的是整棵树
		{
			_root = subR;//更新根节点
		}
		else//将旋转后的子树链接上整个二叉树
		{
			if (pparent->_left == parent)
			{
				pparent->_left = subR;
			}
			else
			{
				pparent->_right = subR;
			}
		}
	}

	void RotateR(Node* parent)//右单旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* pparent = parent->_parent;
		parent->_left = subLR;//更新parent的左节点
		if (subLR)//防止该节点为空
		{
			subLR->_parent = parent;//更新subLR的父节点
		}
		parent->_parent = subL;//更新parent的父节点
		subL->_right = parent;//subL的右子树置为parent
		subL->_parent = pparent;//更新subL的父节点
		if (pparent == nullptr)//旋转的是整棵树
		{
			_root = subL;//更新根节点
		}
		else//将旋转后的子树链接上整个二叉树
		{
			if (pparent->_left == parent)
			{
				pparent->_left = subL;
			}
			else
			{
				pparent->_right = subL;
			}
		}
	}

	void _InOrder(Node* root)
	{
		if (root == NULL)//如果是空树就直接结束
		{
			return;
		}
		_InOrder(root->_left);//先递归遍历其左子树
		cout << root->_kv.first << " ";//再遍历其根节点
		_InOrder(root->_right);//最后递归遍历其右子树
	}

	bool _Check(Node* root, int blackNum, int benchmark)
	{
		if (root == nullptr)
		{
			if (benchmark != blackNum)
			{
				cout << "某条路径黑色节点的数量不相等" << endl;
				return false;
			}

			return true;
		}

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

		if (root->_col == RED
			&& root->_parent
			&& root->_parent->_col == RED)
		{
			cout << "存在连续的红色节点" << endl;
			return false;
		}

		return _Check(root->_left, blackNum, benchmark)
			&& _Check(root->_right, blackNum, benchmark);
	}

private:
	Node* _root = nullptr;
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

php实现截取姓名中的第一个字作为头像的实战记录

php 截取中文字符串第一个字 substr 函数 在 PHP 中&#xff0c;使用 substr 函数来截取中文字符串的第一个字。由于 PHP 默认的字符编码是 UTF-8&#xff0c;它可以正确处理中文字符。 $chineseString "你好世界"; $firstChar substr($chineseString, 0, 1); e…

【小白专用】Apache2.4+PHP8.3+MYSQL的配置

1.下载PHP和Apache 1、PHP下载 PHP For Windows: Binaries and sources Releases 注意&#xff1a; 1.使用Apache作为服务器的话&#xff0c;一定要下载Thread Safe的&#xff0c;否则没有php8apache2_4.dll这个文件&#xff0c; 如果使用IIS的请下载 NON Tread safe的 2.如果…

简单聊聊使用lombok 的争议

大家好&#xff0c;我是G探险者。 项目里&#xff0c;因为我使用了Lombok插件&#xff0c;然后代码走查的时候被领导点名了。 我心想&#xff0c;这么好用的插件&#xff0c;为啥不推广呢&#xff0c;整天写那些烦人的setter&#xff0c;getter方法就不嫌烦么&#xff1f; 领导…

[足式机器人]Part4 南科大高等机器人控制课 Ch05 Instantaneous Velocity of Moving Frames

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;CLEAR_LAB 笔者带更新-运动学 课程主讲教师&#xff1a; Prof. Wei Zhang 南科大高等机器人控制课 Ch05 Instantaneous Velocity of Moving Frames 1.Instantanenous Velocity of Rotating Frames2.Instantanenous Veloc…

计算机视觉 基于Open3D了解用于网格和点云邻域分析的KD树和八叉树

一、简述 距离计算和邻域分析是理解网格和点云的形状、结构和特征的重要工具。我们这里要基于一些3D库来提取基于距离的信息并将其可视化。 与深度图或体素相比,点云和网格表示 3D 空间中的非结构化数据。点由它们的 (X, Y, Z) 坐标表示,在 3D 空间中可能彼此靠近的两…

Vue3:表格单元格内容由:图标+具体内容 构成

一、背景 在Vue3项目中&#xff0c;想让单元格的内容是由 &#xff1a;图标具体内容组成的&#xff0c;类似以下效果&#xff1a; 二、图标 Element-Plus 可以在Element-Plus里面找是否有符合需求的图标iconfont 如果Element-Plus里面没有符合需求的&#xff0c;也可以在这…

什么是缓存穿透、缓存击穿、缓存雪崩,以及各自的解决方案

什么是缓存穿透、缓存击穿、缓存雪崩 缓存雪崩 当缓存数据大面积失效&#xff0c;导致请求无法从缓存中拿到数据而是直接访问数据库。 缓存穿透 缓存穿透是指查询一个缓存中和数据库中都不存在的数据&#xff0c;导致每次查询这条数据都会透过缓存&#xff0c;直接查库&am…

C# Solidworks二次开发:三种获取SW设计结构树的方法-第一讲

今天要讲的方法是如何在Solidworks中获取左侧设计结构上的节点&#xff0c;获取节点的方法我所知道的有三种。 这三种方法满足我在使用过程的多种需求&#xff0c;下面先开始介绍第一个方法&#xff1a; 方法的API如下所示&#xff1a;GetComponents Method (IAssemblyDoc) 这…

安卓上比iOS快捷指令更强大的工具——MacroDroid

使用 MacroDroid (Android) 自动化您的日常生活——一个简单的自动化应用程序&#xff0c;用于在 Android 上自动执行任务以及如何在其上自动执行任务。 iOS 和 Android 之间的区别? iOS和Android是两种不同的移动操作系统&#xff0c;iOS由苹果公司开发&#xff0c;于2007年…

Hexo部署到云服务器后CSS样式无效的问题

Hexo部署到云服务器后CSS样式无效的问题 01 前言 趁活动入手了一个云服务器&#xff08;Linux&#xff09;&#xff0c;打算简单挂个博客上去&#xff0c;因为之前部署到github有了一些经验&#xff0c;所以还是选择使用Hexo。中间步骤略&#xff0c;部署完使用浏览器访问的时…

(六)五种最新算法(SWO、COA、LSO、GRO、LO)求解无人机路径规划MATLAB

一、五种算法&#xff08;SWO、COA、LSO、GRO、LO&#xff09;简介 1、蜘蛛蜂优化算法SWO 蜘蛛蜂优化算法&#xff08;Spider wasp optimizer&#xff0c;SWO&#xff09;由Mohamed Abdel-Basset等人于2023年提出&#xff0c;该算法模型雌性蜘蛛蜂的狩猎、筑巢和交配行为&…

【pycharm】Pycharm中进行Git版本控制

本篇文章主要记录一下自己在pycharm上使用git的操作&#xff0c;一个新项目如何使用git进行版本控制。 文章使用的pycharm版本PyCharm Community Edition 2017.2.4&#xff0c;远程仓库为https://gitee.com/ 1.配置Git&#xff08;File>Settings&#xff09; 2.去Gitee创建…

Elasticsearch 8.9 refresh刷Es缓冲区的数据到Lucene,更新segemnt,使数据可见

一、相关API的handler1、接受HTTP请求的hander(RestRefreshAction)2、往数据节点发送刷新请求的action(TransportRefreshAction)3、数据节点接收主节点refresh传输的action(TransportShardRefreshAction) 二、在IndexShard执行refresh操作1、根据入参决定是使用lucene提供的阻塞…

什么是神经网络的非线性

大家好啊&#xff0c;我是董董灿。 最近在写《计算机视觉入门与调优》&#xff08;右键&#xff0c;在新窗口中打开链接&#xff09;的小册&#xff0c;其中一部分说到激活函数的时候&#xff0c;谈到了神经网络的非线性问题。 今天就一起来看看&#xff0c;为什么神经网络需…

亚马逊云科技re_Invent 2023产品体验:亚马逊云科技产品应用实践 国赛选手带你看Elasticache Serverless

抛砖引玉 讲一下作者背景&#xff0c;曾经参加过国内世界技能大赛云计算的选拔&#xff0c;那么在竞赛中包含两类&#xff0c;一类是架构类竞赛&#xff0c;另一类就是TroubleShooting竞赛&#xff0c;对应的分别为AWS GameDay和AWS Jam&#xff0c;想必也有朋友玩过此类竞赛&…

RTMP流设置超时时间失败

使用FFmpeg(版本是5.0.3&#xff09;将rtmp流作为输入&#xff0c;设置超时时间&#xff08;使用-timeout参数&#xff09;&#xff0c;结果报错&#xff1a;Cannot open Connection tcp://XXX:1935?listen&listen_timeout 通过./ffmpeg -help full 命令查看FFmpeg帮助&am…

【论文笔记】Gemini: A Family of Highly Capable Multimodal Models——细看Gemini

Gemini 【一句话总结&#xff0c;对标GPT4&#xff0c;模型还是transformer的docoder部分&#xff0c;提出三个不同版本的Gemini模型&#xff0c;Ultra的最牛逼&#xff0c;Nano的可以用在手机上。】 谷歌提出了一个新系列多模态模型——Gemini家族模型&#xff0c;包括Ultra…

jenkins设置中文

安装以下两个插件 Locale plugin Localization: Chinese (Simplified) 在jenkins的system配置中找到locale配置项 在locale配置项的默认语言中填入以下内容保存 zh_CN 重启jenkins即可

Gitzip插件【Github免翻下载】

今天给大家推荐一个github下载的插件&#xff0c;平常大家下载应该无外乎就是以下两种&#xff1a; Download zip利用git clone 但是这两种各有各的弊端&#xff0c;前者一般需要科学上网才可以&#xff0c;后者下载不稳定经常中途断掉。 今天给推荐一个款浏览器插件-Gitzip.大…

uniApp应用软件在运行时,不符合华为应用市场审核标准。解决方案合集!

&#xff08;暂时用不到的也建议收藏一下&#xff0c;因为文章持续更新中&#xff09; 最新更改时间&#xff1a;20023-12-10 第一次做App应用开发相信大家一定都遇到过华为应用市场审核的“驳回”&#xff01; 有些问题一看就明白可以立马修改&#xff0c;而有一些问题修改意…