【C++】:红黑树

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关多态的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

​ 

目录

1. 红黑树的概念

2. 红黑树的性质

3. 红黑树节点的定义 

4. 红黑树的插入

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

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

情况一:uncle节点存在且为红

情况二: uncle节点不存在或者存在且为黑

1. p为g的左,且cur为p的左或者p为g的右,且cur为p的右

2. p为g的左,且cur为p的右或者p为g的右,且cur为p的左

5. 红黑树的验证

6. 红黑树的其他接口

7. 红黑树与AVL树的比较

8. 完整代码 


1. 红黑树的概念

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

2. 红黑树的性质

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

3. 红黑树节点的定义 

红黑树节点的定义我们使用pair进行数据的存储,那么这里就存在一个问题,构造出来的节点默认是什么颜色呢?

根据红黑树的性质,每一条路径中黑色节点的数量必须相等,如果构造出来的节点默认设置为黑,那么在一条路径中插入一个黑色节点,为了维持红黑树的规则就需要在别的路径中也加上黑色节点,这样子做的话代价比较大,所以我们将构造出来的节点的颜色默认置为红色,这样子插入一个红色的节点对其他的路径并没有什么影响。

//红黑树节点的定义
template<class K, class V>
struct RBTreeNode
{
	RBTreeNode<K, T>* _left;    //左子树节点
	RBTreeNode<K, T>* _right;   //右子树节点
	RBTreeNode<K, T>* _parent;  //父节点
	Color _col;                 //节点颜色
	pair<K, V> _kv;             //节点的数据

	//节点的构造
	RBTreeNode(const pair<K, T>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_col(RED)
		,_kv(kv)
	{}
};

4. 红黑树的插入

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

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

//插入
	bool Insert(const pair<K, V>& kv)
	{
		//为空可以直接插入,并将根节点置为黑色
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		//不为空找到合适的插入位置
		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
				return false;
		}
		//链接
		//新插入的节点默认为红色节点
		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}

		//...
		
		return true;
	}

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

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

首先我们要了解一下红黑树的基本情况:

cur(c):代表当前节点

parent(p):代表cur的父亲节点

uncle(u):代表cur的叔叔节点

grandfather(g):代表当前节点的祖父节点

情况一:uncle节点存在且为红

注意:这里显示的红黑树有可能是一棵完整的红黑树,也有可能是一棵子树。

这里有三个节点是已知情况,因为插入的默认节点颜色是红色,插入红色时是需要进行调整的,所以cur和parent是红色,那么grandfather节点必定是黑色。

如果叔叔节点存在且为红色,那么只需要进行简单的变色即可,将parent和uncle变为黑色,这时这个子树的每一个路径下的黑色节点就多了一个,因此还需要将grandfather节点变为红色,这样就使它的每一个路径少了一个黑色节点,这样才能平衡多出的黑色节点。

改变完颜色之后,由于我们不确定grandfather节点是否还有父亲节点,如果它的父亲节点为黑色,那么则不需要处理,如果它的父亲为红色节点,那么还需要继续向上处理,为了方便,我们可以将grandfather继续当作cur,继续向上调整。

综上所述:当uncle节点存在且为红色节点时,将parent和uncle改为黑色,然后将grandfather改为红色,再将grandfather继续当作新的cur,继续向上调整。

如果这里已经是一棵完整的红黑树了,此时的cur就变成了根节点,但是它被改成了红色,所以就需要再将根节点置为黑色。

代码实现:

//插入
	bool Insert(const pair<K, V>& kv)
	{
		//和搜索二叉插入同样的逻辑
        //...

		//判断节点的颜色,是否破坏了平衡
		while (parent && parent->_col == RED)
		{
			//祖父节点
			Node* grandfather = parent->_parent;
			//判断父亲与叔叔的位置
			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				//叔叔节点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//将grandfather变为新的cur继续向上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				//其他情况
				//...
			}
			else
			{
				Node* uncle = grandfather->_left;
				//叔叔节点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//将grandfather变为新的cur继续向上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				//其他情况
				//...
			}
		}
        //将根节点再次置黑保持红黑树的平衡
        _root->_col = BLACK;
	}

情况二: uncle节点不存在或者存在且为黑

这里还需要分了两种情况:

1. p为g的左,且cur为p的左或者p为g的右,且cur为p的右

这种情况如果只通过单纯的变色是不能达到效果的,需要配合旋转才能达到红黑树的平衡。

①如果parent为grandfather的左,且cur为parent的左

这种情况需要先以p为根节点进行右单旋,然后进行变色,需要将parent和grandfather变色,将parent变为黑色,将grandfather变为红色。

②如果parent为grandfather的右,且cur为parent的右

这种情况需要先以p为根节点进行左单旋,然后进行变色,需要将parent和grandfather变色,将parent变为黑色,将grandfather变为红色。

2. p为g的左,且cur为p的右或者p为g的右,且cur为p的左

这种情况类似于AVL树中的双旋,通过单旋+变色是不能达到红黑树的平衡的,需要经过两次旋转,再加变色才可以达到红黑树的平衡。

①如果parent为grandfather的左,且cur为parent的右

先以parent为根进行左旋,然后再以grandfather为根进行右旋,然后将cur变黑,将grandfater变红。

②如果parent为grandfather的右,且cur为parent的左

先以parent为根进行右旋,然后再以grandfather为根进行左旋,然后将cur变黑,将grandfather变红。

如果我们仔细观察,不难发现,在上述的两者双旋情况中,在旋转一次之后得到的红黑树和和1中的情况是一样的,那么也就说明了不一定cur是新插入的节点,还有可能是下面的子树在调整完之后将cur变为了红节点,然后导致红黑树的不平衡。

代码演示:

左单旋和右单旋就不做过多解释了,AVL树部分有详细的介绍。

//插入
	bool Insert(const pair<K, V>& kv)
	{
		//为空可以直接插入,并将根节点置为黑色
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		//不为空找到合适的插入位置
		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
				return false;
		}
		//链接
		//新插入的节点默认为红色节点
		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = 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)
				{
					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//将grandfather变为新的cur继续向上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else  //叔叔节点不存在或者存在且为黑
				{
					if (cur == parent->_left)   //该路径的parent已经是grandfather的左
					{
						//旋转+变色
						Rotate_right(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else                       //cur是parent的右
					{
						//双旋+变色
						Rotate_left(parent);
						Rotate_right(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
			else //parent == grandfather->_right
			{
				Node* uncle = grandfather->_left;
				//叔叔节点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//将grandfather变为新的cur继续向上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)   //该路径的parent已经是grandfather的右
					{
						//旋转+变色
						Rotate_left(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else                        //cur是parent的左
					{
						Rotate_right(parent);
						Rotate_left(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
		}
		//将根节点再次置黑保持红黑树的平衡
		_root->_col = BLACK;
		
		return true;
	}

5. 红黑树的验证

红黑树的检测分为两步:

  • 1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)
  • 2. 检测其是否满足红黑树的性质

中序遍历比较简单,就不做赘述了,主要来看一下第二条:

首先红黑树的性质:

  • 1. 每个结点不是红色就是黑色
  • 2. 根节点是黑色的
  • 3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  • 4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点

①因为我们对颜色使用的是枚举,所以每个节点不是红色就是黑色。

②根节点是否为黑色只需要对_root的_col判断是否为黑色即可。

③判断是否存在连续的红色节点可以通过判断一个节点的父亲节点是否为红色即可。

④判断每条路径是否具有相同的黑色节点可以封装一个函数,然后传递一个路径中黑色节点的个数作为基准值,通过判断剩余路径黑色节点的个数与这个基准值相不相等即可。求每条路径的个数可以采用深度优先遍历找到黑色节点计数器++即可。

代码演示:

//判断是否平衡
	bool IsBalance()
	{
		if (_root == nullptr)
			return true;
		//1.判断根是否为黑
		if (_root->_col == RED)
			return false;

		int standard_val = 0;  	//最左路径的黑色节点个数
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				standard_val++;
			cur = cur->_left;
		}
		int Black_size = 0;
		return Check(_root,standard_val,Black_size);
	}
private:
	//判断是否平衡
	bool Check(Node* root, const int standard_val, int Black_size)
	{
		if (root == nullptr)
		{
			if (Black_size != standard_val)   //比较黑色节点的个数
			{
				cout << "存在黑色节点数量不相等的路径" << endl;
				return false;
			}
			else
				return true;
		}
		//判断它与它父亲的颜色
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "有连续的红色节点" << endl;

			return false;
		}
		//黑色节点计数器++
		if (root->_col == BLACK)
		{
			Black_size++;
		}
		//递归它的左右子树
		return Check(root->_left, standard_val, Black_size)
			&& Check(root->_right, standard_val, Black_size);
	}

6. 红黑树的其他接口

红黑树的查找、节点个数、树的高度

	//高度
	int Height()
	{
		return _Height(_root);
	}
	//节点个数
	size_t Size()
	{
		return _Size(_root);
	}
	//查找
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < key)
			{
				cur = cur->_right;
			}
			else if (cur->_kv.first > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return NULL;
	}
private:
	size_t _Size(Node* root)
	{
		if (root == NULL)
			return 0;

		return _Size(root->_left)
			+ _Size(root->_right) + 1;
	}
	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);

		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

7. 红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(\log N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

8. 完整代码 

#pragma once

//枚举定义节点颜色
enum Color 
{
	RED,    //红色
	BLACK   //黑色
};

//红黑树节点的定义
template<class K, class V>
struct RBTreeNode
{
	RBTreeNode<K, V>* _left;    //左子树节点
	RBTreeNode<K, V>* _right;   //右子树节点
	RBTreeNode<K, V>* _parent;  //父节点
	Color _col;                 //节点颜色
	pair<K, V> _kv;             //节点的数据

	//节点的构造
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_col(RED)
		,_kv(kv)
	{}
};

//红黑树的实现
template<class K, class V>
class RBTree
{
public:
	typedef RBTreeNode<K, V> Node;
	//插入
	bool Insert(const pair<K, V>& kv)
	{
		//为空可以直接插入,并将根节点置为黑色
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		//不为空找到合适的插入位置
		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
				return false;
		}
		//链接
		//新插入的节点默认为红色节点
		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = 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)
				{
					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//将grandfather变为新的cur继续向上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else  //叔叔节点不存在或者存在且为黑
				{
					if (cur == parent->_left)   //该路径的parent已经是grandfather的左
					{
						//旋转+变色
						Rotate_right(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else                       //cur是parent的右
					{
						//双旋+变色
						Rotate_left(parent);
						Rotate_right(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
			else //parent == grandfather->_right
			{
				Node* uncle = grandfather->_left;
				//叔叔节点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//将grandfather变为新的cur继续向上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)   //该路径的parent已经是grandfather的右
					{
						//旋转+变色
						Rotate_left(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else                        //cur是parent的左
					{
						Rotate_right(parent);
						Rotate_left(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
		}
		//将根节点再次置黑保持红黑树的平衡
		_root->_col = BLACK;
		return true;
	}

	//中序遍历
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	//判断是否平衡
	bool IsBalance()
	{
		if (_root == nullptr)
			return true;
		//1.判断根是否为黑
		if (_root->_col == RED)
			return false;

		int standard_val = 0;  	//最左路径的黑色节点个数
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				standard_val++;
			cur = cur->_left;
		}
		int Black_size = 0;
		return Check(_root,standard_val,Black_size);
	}
	//高度
	int Height()
	{
		return _Height(_root);
	}
	//节点个数
	size_t Size()
	{
		return _Size(_root);
	}
	//查找
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < key)
			{
				cur = cur->_right;
			}
			else if (cur->_kv.first > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return NULL;
	}
private:
	size_t _Size(Node* root)
	{
		if (root == NULL)
			return 0;

		return _Size(root->_left)
			+ _Size(root->_right) + 1;
	}
	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);

		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}
	//判断是否平衡
	bool Check(Node* root, const int standard_val, int Black_size)
	{
		if (root == nullptr)
		{
			if (Black_size != standard_val)   //比较黑色节点的个数
			{
				cout << "存在黑色节点数量不相等的路径" << endl;
				return false;
			}
			else
				return true;
		}
		//判断它与它父亲的颜色
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "有连续的红色节点" << endl;

			return false;
		}
		//黑色节点计数器++
		if (root->_col == BLACK)
		{
			Black_size++;
		}
		//递归它的左右子树
		return Check(root->_left, standard_val, Black_size)
			&& Check(root->_right, standard_val, Black_size);
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}
	//右单旋
	void Rotate_right(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		if(subLR)
			subLR->_parent = parent;
		Node* ppNode = parent->_parent;
		subL->_right = parent;
		parent->_parent = subL;
		if (parent == _root)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
				subL->_parent = ppNode;
			}
			else
			{
				ppNode->_right = subL;
				subL->_parent = ppNode;
			}
		}
	}

	//左单旋
	void Rotate_left(Node* parent)
	{
		Node* subR = parent->_right;  
		Node* subRL = subR->_left; 
		Node* ppNode = parent->_parent;
		subR->_left = parent;
		parent->_parent = subR;

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;
		if (_root == parent)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
				ppNode->_left = subR;
			else
				ppNode->_right = subR;
			subR->_parent = ppNode;
		}
	}
private:
	Node* _root = nullptr;
};

朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!   

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

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

相关文章

12.视图

目录 1.视图的含义与作用 2.视图的创建与查看 1.创建视图的语法形式 2、查看视图&#xff1a; 1.使用DESCRIBE语句查看视图基本信息 2.使用SHOW TABLE STATUS语查看视图基本信息查看视图的信息 3.使用SHOW CREATE VIEW语查看视图详细信息 4.在views表中查看视图详细信息…

【合集】SpringBoot——Spring,SpringBoot,SpringCloud相关的博客文章合集

前言 本篇博客是spring相关的博客文章合集&#xff0c;内容涵盖Spring&#xff0c;SpringBoot&#xff0c;SpringCloud相关的知识&#xff0c;包括了基础的内容&#xff0c;比如核心容器&#xff0c;springMVC&#xff0c;Data Access&#xff1b;也包括Spring进阶的相关知识&…

智能优化算法应用:基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.正余弦算法4.实验参数设定5.算法结果6.参考文…

【数电笔记】54-或非门构成的基本RS触发器

目录 说明&#xff1a; 1. 电路组成 2. 逻辑功能 3. 特性表 4. 特性方程 5. 例题 6. 两种基本RS触发器的形式比 说明&#xff1a; 笔记配套视频来源&#xff1a;B站&#xff1b;本系列笔记并未记录所有章节&#xff0c;只对个人认为重要章节做了笔记&#xff1b;标题前…

NAND闪存价格暴涨:512GB芯片翻倍,256GB涨幅达55%

此前&#xff0c;根据Trendforce的信息&#xff0c;今年第四季度NAND的合约价预计上涨8-13%&#xff0c;其中Wafer上涨13-18%。 根据DRAMeXchange最新的数据表明&#xff0c;之前预测的数据还是太保守了&#xff0c;过去一年Wafer NAND价格如下图&#xff1a; DRAM/NAND价格近几…

体系化学习运筹学基础算法的实践和总结

文章目录 引言目标设计目标实践文章汇总经验总结一则预告 引言 眨眼间已经12月了&#xff0c;眼看着2023年马上要过完了。 女朋友最近总说&#xff0c;工作以后感觉时间过的好快。事实上&#xff0c;我也是这么认为的。年纪越大&#xff0c;越会担心35岁危机的降临。所以&…

CESM笔记——component活动状态+compset前缀解析+B1850,BHIST区别

时隔一年没写CSDN笔记了&#xff0c;一些CESM的知识点我都快忘了。诶&#xff0c;主要是在国外办公室的网屏蔽了好多国内的网络&#xff0c;CSDN登不上&#xff0c;回家又不想干活。。。好吧&#xff0c;好多借口。。。 昨天师弟问我一些问题&#xff0c;想想要不可以水一篇小…

MySQL进阶学习--day01

存储引擎介绍 1. MySQL体系结构2. 存储引擎介绍2.1 存储引擎操作2.2 示例演示 1. MySQL体系结构 连接层&#xff08;Connection Layer&#xff09;&#xff1a;连接层主要负责与客户端建立连接&#xff0c;并进行用户身份验证和权限验证。在这一层&#xff0c;MySQL 接收来自客…

postgresql安装部署(docker版本)

1.在线部署 创建数据库存储目录 mkdir /home/pgdata创建容器 docker run --name postgresql --restartalways -d -p 5432:5432 -v /home/pgdata:/var/lib/postgresql/data --shm-size10g -e POSTGRES_PASSWORD密码 postgis/postgis:12-3.2-alpine–name为设置容器名称 -d表…

网页设计中增强现实的兴起

目录 了解增强现实 增强现实的历史背景 AR 和网页设计的交叉点 AR 在网页设计中的优势 增强参与度和互动性 个性化的用户体验 竞争优势和品牌差异化 AR 在网页设计中的用例 结论 近年来&#xff0c;增强现实已成为一股变革力量&#xff0c;重塑了我们与数字领域互动的方式。它被…

每天五分钟计算机视觉:使用1*1卷积层来改变输入层的通道数量

本文重点 在卷积神经网络中有很多重要的卷积核&#xff0c;比如1*1的卷积核&#xff0c;3*3的卷积核&#xff0c;本文将讲解1*1的卷积核的使用&#xff0c;它在卷积神经网络中具有重要的地位。由于1*1的卷积核使用了最小的窗口&#xff0c;那么1*1的卷积核就失去了卷积层可以识…

QEMU环境调试方法

目录 1.如何查看makefile构建过程执行的命令&#xff1f; 2.如何使用GCC生成C程序的宏展开文件&#xff1f; 3.如何在qemu中执行特定的可执行程序&#xff1f; 4.如何在qemu中直接运行可执行程序&#xff1f; 5.如何在qemu中调试某个可执行程序&#xff1f; 本文从调试的角…

Linux的权限

Linux的权限 一、shell运行原理--外壳程序二、Linux权限&#xff08;主体&#xff0c;重点&#xff09;三、常见的权限问题目录权限umask粘滞位 一、shell运行原理–外壳程序 为什么我们不是直接访问的操作系统&#xff1f; 1.人不善于直接使用操作系统 2.如果让人直接访问操作…

阵列信号处理-波束方向图参数

波束方向图的参数有&#xff1a; 3dB带宽(半功率波束宽度&#xff0c;HPBW&#xff0c;half-power beamwidth)到第一零点距离(这个距离的两倍称为 B W N N BW_{NN} BWNN​)到第一旁瓣的距离第一旁瓣的高度其余零点的位置旁瓣的衰减速率栅瓣 波束方向图的主波束 3dB波束宽度 3…

reinforce 跑 CartPole-v1

gym版本是0.26.1 CartPole-v1的详细信息&#xff0c;点链接里看就行了。 修改了下动手深度强化学习对应的代码。 然后这里 J ( θ ) J(\theta) J(θ)梯度上升更新的公式是用的不严谨的&#xff0c;这个和王树森书里讲的严谨公式有点区别。 代码 import gym import torch from …

React基础语法整理

安装&#xff1a; yarn create react-app reatc-lesson --template typescript yarn create 创建一个react-app的应用 项目名称 typescript 的模板react-app 官方地址 https://create-react-app.bootcss.com/docs/adding-typescriptreact 语法文档 https://zh-hans.react.dev…

12.9文档记录——脱欧建模

4 脱欧对英国整体的影响 4.1 脱欧影响评估模型 4.1.1 指标的确定和数据的收集 为了建立指标体系&#xff0c;我们需要选择有代表性的指标。在有关脱欧的大量研究基础上[1]&#xff0c;考虑到脱欧对英国经济、民生、国际影响等各个方面影响&#xff0c;我们最终在兼顾模型有效…

表格的介绍与实战(详细且有案例)

目录​​​​​​​​​​​​​​ 表格的主要作用&#xff1a; 表格的基本语法&#xff1a; 表格相关的标签 合并单元格&#xff1a; 实战&#xff1a; 表格的主要作用&#xff1a; 表格主要是用来展示数据的&#xff0c;使用表格来展示数据&#xff0c;数据可读性更好…

大数据HCIE成神之路之数据预处理(1)——缺失值处理

缺失值处理 1.1 删除1.1.1 实验任务1.1.1.1 实验背景1.1.1.2 实验目标1.1.1.3 实验数据解析 1.1.2 实验思路1.1.3 实验操作步骤1.1.4 结果验证 1.2 填充1.2.1 实验任务1.2.1.1 实验背景1.2.1.2 实验目标1.2.1.3 实验数据解析 1.2.2 实验思路1.2.3 实验操作步骤1.2.4 结果验证 1…

基于Solr的全文检索系统的实现与应用

文章目录 一、概念1、什么是Solr2、与Lucene的比较区别1&#xff09;Lucene2&#xff09;Solr 二、Solr的安装与配置1、Solr的下载2、Solr的文件夹结构3、运行环境4、Solr整合tomcat1&#xff09;Solr Home与SolrCore2&#xff09;整合步骤 5、Solr管理后台1&#xff09;Dashbo…
最新文章