【C++】红黑树

2023-10-29

MarkDown输出x的平方和log以2为底的方法:
1、x2——英文输入法,输入x 加 ^ 加 2 加 ^
2、log2N——英文输入法,输入log 加 ~ 加 2 加 ~ 加 N


1、红黑树概念

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

也就是说:红黑树中,最长的路径不超过最短路径的2倍

下面是红黑树的样例:
在这里插入图片描述

2、红黑树的性质

通过上面红黑树的概念加图片我们可以得到几个红黑树的性质(参考上面图片来观察):

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

思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?

最长路径:一黑一红相间的路径
最短路径:一条路径节点全黑

这样一看,最长的路径节点个数不会超过最短路径节点个数的两倍

极端情况下的近似平衡

最优情况:左右平衡。路径全黑或者每一条路径都是一黑一红相间的路径。满二叉树
最差情况:左右不平衡。左子树全黑,右子树一黑一红

全黑路径长度是h
2^h -1 + 红节点 = N(这里红节点远小于黑节点)
最短路径:log2N
最长路径:2*log2N

如果N是10亿,那么最短路径为30,最长路径为60,对于计算机来说30和60是在同一个量级的,所以差别并不大
在这里插入图片描述

所以:红黑树并没有AVL树那么严格,看起来就没有AVL树那么平衡,查找的效率也就没有AVL树那么高效(对比于AVL树来说)
但是AVL树高效的查找,是依赖于AVL严格的平衡,严格的平衡是通过不断旋转得到的,而旋转消耗是比较大的。而红黑树不那么平衡就表明红黑树没有AVL那么多次的旋转操作,消耗也就比较小了

3、红黑树的实现

3-1、红黑树节点的定义

enum colors
{
	RED,
	BLOCK,
};
template <class K, class V>
class RBTreeNode
{
public:
	pair<K, V> _kv;
	RBTreeNode<K, V>* _left;//左节点
	RBTreeNode<K, V>* _right;//右节点
	RBTreeNode<K, V>* _parent;//父节点

	colors _col;

	//初始化
	RBTreeNode(const pair<K, V>& kv)
		:_kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _col(RED)
	{}
};

3-2、红黑树的插入

红黑树的插入和AVL树的插入前面大差不差,就算少了平衡因子,多了颜色

template <class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)//前面与AVL树一样
		{
			_root = new Node(kv);
			_root->_col = BLOCK;//根节点是黑色的
			return true;
		}
		Node* parent = nullptr;//parent是cur的父节点
		Node* cur = _root;//cur往下走
		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;//不存在找到,因为AVL树不允许有重复值
			}
		}
		走到这里就表示找到我们要插入kv值的正确位置了
		cur = new Node(kv);

		cur->_col = RED;//这里插入一个节点,颜色设置为红色!!!
		//插入一个节点,设置为红色。我们就违背了红黑树规则3(红黑树的性质那里)
		//插入一个节点,设置为黑色。我们就违背了红黑树规则4
		// 
		//但是,我们可以仔细观察,发现违背规则3然后对红黑树进行修改,比违背规则4进行修改简单的多!!!
		//而且插入设置为红色不一定破环了规则3,就算违背规则3破坏的是一条路径,
		//而规则4是整棵树的全部路径。所以这里设置节点为红色比较容易控制

		if (parent->_kv.first < kv.first)//如果new的节点比父节点大,那么父节点的右指针指向new节点
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else//如果new的节点比父节点小,那么父节点的左指针指向new节点
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		//....开始插入了
		return true;
	}
private:
	Node* _root = nullptr;
};

我们先来看看下面的插入操作有哪些情况:

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

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

3-2-1、情况一

情况一: cur为红,p为红,g为黑,u存在且为红
这里g一定为黑,因为如果g为红,那么p为红的时候我们就要对p进行修改了,而cur是我们新增的红,
所以我们这个时候破坏了规则,开始对cur,p,g和u节点进行变色

在这里插入图片描述

cur和p均为红,违反了性质三,此处能否将p直接改为黑?

解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整

我们再来看看abcde(abcde可能有这无数层,这里我们就只是举个样例):
1、abcde为空:
在这里插入图片描述
这个时候就和上面的处理情况一样了

2、abcde不为空

a、b为红:
在这里插入图片描述
c、d、e情况(后面还可能带着节点):
在这里插入图片描述
这个时候在a、b下面新增节点:
在这里插入图片描述
这个时候就也变得和上面情况一样的,直接将p,u改为黑,g改为红,然后把g当成cur,继续向上调整

情况一变情况一
在这里插入图片描述

当然,我们把g当成cur向上调整,或者新插入红节点,并不就一定是上面的情况,比如cur为,u不为红。这个时候我们就要继续找其他的处理方法了!

3-2-2、情况二

情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑

1、u不存在,那么cur就算新增节点
在这里插入图片描述
这个时候:

p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转p、g变色–p变黑,g变红

在这里插入图片描述
2、u存在且u为黑,cur不是新增
这个时候cur不是新增节点了,因为p为红,u为黑,路径的黑节点数据个数不一样了!

在这里插入图片描述
情况一变情况二
这个时候就算上面的情况1了,我们进行处理:
在这里插入图片描述

注意:u存在且为黑,那么p和cur一定是由情况一变过来,p和cur为红的,因为如果开始p和cur为红,路径的黑节点数据个数不一样了

这个时候,我们就和处理abcde都不存在的方法一样了,p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转p、g变色–p变黑,g变红
在这里插入图片描述

在这里插入图片描述
p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转p、g变色–p变黑,g变红

3-2-3、情况三

情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑

1、u不存在,cur是新增
在这里插入图片描述
如果cur新增在p左边,那么就变成了情况二
如果新增在p的右变,这个时候就要进行双旋
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
这个时候就旋转成为了情况二
在这里插入图片描述
在进行第二次旋转
在这里插入图片描述

2、u存在且为黑,cur不是新增

情况一变情况三
在这里插入图片描述
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转

在这里插入图片描述
二次旋转
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转,则转换成了情况2
在这里插入图片描述
针对每种情况进行相应的处理即可

以上就是我们对红黑树的插入情况的分析,就算从AVL树的旋转加调整平衡因子,变成了旋转加变色

继续上面的代码:

while (parent && parent->_col == RED)//父亲颜色为黑就不需要处理了,颜色为红就要处理
		{
			Node* gf = parent->_parent;//
			if (parent == gf->_left)
			{
				Node* uncle = gf->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLOCK;
					gf->_col = RED;
					cur = gf;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_left)
					{
						//新增cur在父亲的左,右单旋
						RotateR(gf);
						parent->_col = BLOCK;
						gf->_col = RED;
					}
					else
					{
						//情况三,双旋
						RotateL(parent);
						RotateR(gf);
						cur->_col = BLOCK;
						gf->_col = RED;
					}
					break;//这里要break,因为这一层已经处理完了,上面有问题是上面的事,与这一层无关
				}
			}
			else
			{
				Node* uncle = gf->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLOCK;
					gf->_col = RED;

					cur = gf;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)
					{
						RotateL(gf);
						parent->_col = BLOCK;
						gf->_col = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(gf);
						cur->_col = BLOCK;
						gf->_col = RED;
					}

					break;
				}
			}
		}
		_root->_col = BLOCK;

动态图

这里展示一下动态构建红黑树的演示图:
1、升序插入构建红黑树
在这里插入图片描述
2、降序插入构建红黑树
在这里插入图片描述
3、随机插入构建红黑树
在这里插入图片描述
4、右旋转
在这里插入图片描述

5、左旋转
在这里插入图片描述

4、红黑树的验证

这里我们不能直接比较最长路径和最短路径的差值,要缺点红黑树的规则全部正确才能证明该树是红黑树

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 (没有连续的红节点)
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点 (每条路径的黑节点个数相同)
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
bool Check(Node* root, int blackNum, const int ref)
	{
		if (root == nullptr)
		{
			//cout << blackNum << endl;
			if (blackNum != ref)
			{
				cout << "违反规则:本条路径的黑色节点的数量跟最左路径不相等" << endl;
				return false;
			}
			return true;
		}
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "违反规则:出现连续红色节点" << endl;
			return false;
		}
		if (root->_col == BLOCK)
		{
			++blackNum;
		}
		return Check(root->_left, blackNum, ref) && Check(root->_right, blackNum, ref);
	}
	bool IsBalance()判断是否为红黑树,这里的IsBalance不是递归函数
	{
		if (_root == nullptr)//这里不需要递归,所以就使用_root,不用传参
			return true;
		if (_root->_col != BLOCK)//这里判断的是整棵树的根,不是每一个根都要为黑,
								//所以我们要再写一个函数来处理
			return false;

		int ref = 0;
		Node* left = _root;
		while (left)
		{
			if (left->_col == BLOCK)
				++ref;
			left = left->_left;
		}
		return Check(_root, 0, ref);
	}

5、红黑树的删除

与AVL树一样,我们不需要对红黑树的删除有深入的理解
所以红黑树的删除本节不做讲解,有兴趣的同学可参考:《算法导论》或者《STL源码剖析》
博客园地址

6、 红黑树与AVL树的比较

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

7、红黑树的应用

  1. C++ STL库 – map/set、mutil_map/mutil_set
  2. Java 库
  3. linux内核
  4. 其他一些库

8、红黑树代码

#pragma once
#include <assert.h>
#include <time.h>
using namespace std;
enum colors
{
	RED,
	BLOCK,
};
template <class K, class V>
class RBTreeNode
{
public:
	pair<K, V> _kv;
	RBTreeNode<K, V>* _left;//左节点
	RBTreeNode<K, V>* _right;//右节点
	RBTreeNode<K, V>* _parent;//父节点

	colors _col;

	//初始化
	RBTreeNode(const pair<K, V>& kv)
		:_kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _col(RED)
	{}
};

template <class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)//前面与AVL树一样
		{
			_root = new Node(kv);
			_root->_col = BLOCK;//根节点是黑色的
			return true;
		}
		Node* parent = nullptr;//parent是cur的父节点
		Node* cur = _root;//cur往下走
		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;//不存在找到,因为AVL树不允许有重复值
			}
		}
		走到这里就表示找到我们要插入kv值的正确位置了
		cur = new Node(kv);

		cur->_col = RED;//这里插入一个节点,颜色设置为红色!!!
		//插入一个节点,设置为红色。我们就违背了红黑树规则3(红黑树的性质那里)
		//插入一个节点,设置为黑色。我们就违背了红黑树规则4
		// 
		//但是,我们可以仔细观察,发现违背规则3然后对红黑树进行修改,比违背规则4进行修改简单的多!!!
		//而且插入设置为红色不一定破环了规则3,就算违背规则3破坏的是一条路径,
		//而规则4是整棵树的全部路径。所以这里设置节点为红色比较容易控制

		if (parent->_kv.first < kv.first)//如果new的节点比父节点大,那么父节点的右指针指向new节点
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else//如果new的节点比父节点小,那么父节点的左指针指向new节点
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		while (parent && parent->_col == RED)//父亲颜色为黑就不需要处理了,颜色为红就要处理
		{
			Node* gf = parent->_parent;//
			if (parent == gf->_left)
			{
				Node* uncle = gf->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLOCK;
					gf->_col = RED;
					cur = gf;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_left)
					{
						//新增cur在父亲的左,右单旋
						RotateR(gf);
						parent->_col = BLOCK;
						gf->_col = RED;
					}
					else
					{
						//情况三,双旋
						RotateL(parent);
						RotateR(gf);
						cur->_col = BLOCK;
						gf->_col = RED;
					}
					break;//这里要break,因为这一层已经处理完了,上面有问题是上面的事,与这一层无关
				}
			}
			else
			{
				Node* uncle = gf->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLOCK;
					gf->_col = RED;

					cur = gf;
					parent = cur->_parent;
				}
				else
				{
					if (cur == parent->_right)
					{
						RotateL(gf);
						parent->_col = BLOCK;
						gf->_col = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(gf);
						cur->_col = BLOCK;
						gf->_col = RED;
					}

					break;
				}
			}
		}
		_root->_col = BLOCK;
		return true;
	}
	void RotateL(Node* parent)
	{
		Node* subr = parent->_right;
		Node* subrl = subr->_left;
		parent->_right = subrl;
		if (subrl)//上面的节点不可能为空,但是这里的subrl可能为空
		{
			subrl->_parent = parent;
		}
		Node* ppnode = parent->_parent;
		subr->_left = parent;
		parent->_parent = subr;
		if (ppnode == nullptr)//如果
		{
			_root = subr;
			_root->_parent = nullptr;//这里要置空
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subr;
			}
			else
			{
				ppnode->_right = subr;
			}
			subr->_parent = ppnode;
		}
	}
	void RotateR(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 (ppnode == nullptr)
		{
			_root = subl;
			subl->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subl;
			}
			else
			{
				ppnode->_right = subl;
			}
			subl->_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)
		{
			//cout << blackNum << endl;
			if (blackNum != ref)
			{
				cout << "违反规则:本条路径的黑色节点的数量跟最左路径不相等" << endl;
				return false;
			}
			return true;
		}
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "违反规则:出现连续红色节点" << endl;
			return false;
		}
		if (root->_col == BLOCK)
		{
			++blackNum;
		}
		return Check(root->_left, blackNum, ref) && Check(root->_right, blackNum, ref);
	}
	bool IsBalance()判断是否为红黑树,这里的IsBalance不是递归函数
	{
		if (_root == nullptr)//这里不需要递归,所以就使用_root,不用传参
			return true;
		if (_root->_col != BLOCK)//这里判断的是整棵树的根,不是每一个根都要为黑,
								//所以我们要再写一个函数来处理
			return false;

		int ref = 0;
		Node* left = _root;
		while (left)
		{
			if (left->_col == BLOCK)
				++ref;
			left = left->_left;
		}
		return Check(_root, 0, ref);
	}
private:
	Node* _root = nullptr;
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++】红黑树 的相关文章

  • Qt - QProcess 不工作

    我尝试启动 Internet Explorer 所以我使用下面的代码 QProcess process new QProcess this QString temp C Program Files Internet Explorer iex
  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • C# 方法重载决策不选择具体的泛型覆盖

    这个完整的 C 程序说明了这个问题 public abstract class Executor
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 现代 C++ 编译器是否能够在某些情况下避免调用 const 函数两次?

    例如 如果我有以下代码 class SomeDataProcessor public bool calc const SomeData d1 const SomeData d2 const private Some non mutable
  • 有些有助于理解“产量”

    在我不断追求少吸的过程中 我试图理解 产量 的说法 但我不断遇到同样的错误 someMethod 的主体不能是迭代器块 因为 System Collections Generic List 不是迭代器接口类型 这是我被卡住的代码 forea
  • 处理右值时的 insert 与 emplace

    std string myString std unordered set
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • 如何使用 ASP.NET Core 获取其他用户的声明

    我仍在学习 ASP NET Core 的身份 我正在进行基于声明的令牌授权 大多数示例都是关于 当前 登录用户的 就我而言 我的 RPC 服务正在接收身份数据库中某个用户的用户名和密码 我需要 验证是否存在具有此类凭据的用户 获取该用户的所
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 模板外部链接?谁能解释一下吗?

    模板名称具有链接 3 5 非成员函数模板可以有内部链接 任何其他模板名称应具有外部链接 从具有内部链接的模板生成的实体与在其他翻译单元中生成的所有实体不同 我知道使用关键字的外部链接 extern C EX extern C templat
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • 如何最好地以编程方式将 `__attribute__ ((unused))` 应用于这些自动生成的对象?

    In my makefile我有以下目标 它将文本 HTML 资源 编译 为unsigned char数组使用xxd i http linuxcommand org man pages xxd1 html 我将结果包装在匿名命名空间和标头保
  • 如何在 C# 中创建异步方法?

    我读过的每一篇博客文章都会告诉您如何在 C 中使用异步方法 但由于某些奇怪的原因 从未解释如何构建您自己的异步方法来使用 所以我现在有这段代码使用我的方法 private async void button1 Click object se
  • Visual Studio 2015:v120 与 v140?

    仅供参考 Win10 x64 我今天开始尝试 Visual Studio 2015 在弄清楚如何运行 C C 部分后 我尝试加载一个大型个人项目 该项目使用非官方的glsdk http glsdk sourceforge net docs
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • 代码中的.net Access Forms身份验证“超时”值

    我正在向我的应用程序添加注销过期警报 并希望从我的代码访问我的 web config 表单身份验证 超时 值 我有什么办法可以做到这一点吗 我认为您可以从 FormsAuthentication 静态类方法中读取它 这比直接读取 web c
  • 为什么空循环使用如此多的处理器时间?

    如果我的代码中有一个空的 while 循环 例如 while true 它将把处理器的使用率提高到大约 25 但是 如果我执行以下操作 while true Sleep 1 它只会使用大约1 那么这是为什么呢 更新 感谢所有精彩的回复 但我
  • 在 System.Type 上使用条件断点时出错

    这是函数 public void Init System Type Type this Type Type BuildFieldAttributes BuildDataColumns FieldAttributes 我在第一行设置了一个断点
  • 当用户更改 Windows 中的语言键盘布局时如何通知?

    I want to show a message to user when the user changes the language keyboard layout of Windows for example from EN to FR

随机推荐

  • 【CTF】CTFshow-SQL注入(持续更新)

    CTF CTFshow SQL注入 持续更新 就剩一年的大学时光了 最近也很迷茫 想找实习 又得考托福 又想提前开始毕设 假期前又要上学校安排的实训 马上还又有一门考试 事情一堆 但又感觉整天不知道自己应该做什么 在过完了我给自己安排的两个
  • 数字图像处理之配置opencv中遇到的问题

    现在网络上有很多的教程 上面有配置opnecv的教程有很多 综合其中的优点便可以配置成功 参考教程 配置系统变量 http wenku baidu com link url 8J6XO19h3dncpZRXgAY JBmpsgVsNtZEs
  • vue插件开发(时间播放器),发布到npm

    起因 因项目需要一个时间轴播放插件 根据时间渲染一些数据 从网上也查找了许多 但大多不太合适 所以想自己开发一个并发布到npm 本篇文章主要介绍过将组件发布到npm的过程 如看组件源码 项目源码 文档 1 项目初始化 首先 要创建项目 封装
  • 企业网络安全:威胁检测和响应 (TDR)

    什么是威胁检测和响应 威胁检测和响应 TDR 是指识别和消除 IT 基础架构中存在的恶意威胁的过程 它涉及主动监控 分析和操作 以降低风险并防止未经授权的访问 恶意活动和数据泄露 以免它们对组织的网络造成任何潜在损害 威胁检测使用自动安全工
  • map在put的时候,key相同,value 做成list 加入

    map在put的时候 key相同 value 做成list 加入 param map param key param value public static void putValueToList Map
  • BFC块级格式化上下文

    BFC块级格式化上下文 BFC 的一些核心特性 如何创建 BFC 疑问 1 外边距折叠是什么 2 BFC外边距到底折不折叠 特性3 4冲突 3 为什么float的值不为none可以创建BFC 4 为什么position值为absolute或
  • Spark SQL创建Mysql映射表,直接通过jdbc查询混合数据源

    CREATE TABLE db name mysql tb mapping USING org apache spark sql jdbc OPTIONS url jdbc mysql xxx xxx xxx xxx 3306 db nam
  • 【华为OD统一考试B卷

    在线OJ 已购买本专栏用户 请私信博主开通账号 在线刷题 运行出现 Runtime Error 0Aborted 请忽略 华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一
  • IDEA插件系列(29):Easy Javadoc插件——快速生成javadoc文档注释

    1 插件介绍 Easy Javadoc插件 能帮助java开发者自动生成javadoc文档注释 如下 2 安装方式 第一种安装方式是在线下载安装插件 第二种安装方式是使用离线插件进行安装 插件下载地址 https plugins jetbr
  • MySQL优化(一):MySQL架构与SQL执行流程

    目录 一 一条查询SQL语句是如何执行的 1 通信协议 1 1 通信协议 通信类型 同步或异步 连接方式 长连接或者短连接 通信协议 1 2 通信方式 2 查询缓存 3 语法解析和预处理 Parser Preprocessor 3 1 词法
  • 十二种常见设计模式代码详解

    零 设计模式分类 设计模式有创建型模式 结构型模式与行为型模式 创建型 单例模式 工厂模式 简单工厂 工厂方法 抽象工厂 结构型 适配器模式 门面模式 装饰器模式 注册树模式 代理模式 管道模式 行为型 策略模式 观察者模式 命令模式 迭代
  • SVN服务器搭建和使用(二)

    上一篇介绍了VisualSVN Server和TortoiseSVN的下载 安装 汉化 这篇介绍一下如何使用VisualSVN Server建立版本库 以及TortoiseSVN的使用 首先打开VisualSVN Server Manage
  • [Pytorch系列-51]:循环神经网络RNN - torch.nn.RNN类的参数详解与代码示例

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 121505015 目录 第1章 RNN
  • 四书 - 中庸

    天命之谓性 率性之谓道 修道之谓教 道也者 不可须臾离也 可离非道也 是故君子戒慎乎其所不睹 恐惧乎其所不闻 莫见乎隐 莫显乎微 故君子慎其独也 喜怒哀乐之未发 谓之中 发而皆中节 谓之和 中也者 天下之大本也 和也者 天下之达道也 致中和
  • 优化分页查询

    前言 很多时候 我们写分页查询的时候 只是单纯的想把结果查询出来就好了 但是有没有想过 自己写的分页查询效率会怎么 数据少的是没太大影响 但是多了就会有影响了 所以这篇简单介绍下分页查询的一些基本优化 比如下面的sql select a b
  • 定时超时任务

    一个有用的类 Description ClassName TaskRunnable Date 2022 1 27 16 53 Author 王东平 Slf4j public class Task 任务ID private String id
  • 将数据库中的数据导出为excel表格——java学习笔记

    最近我的项目增加了一个需求 需要将数据库中的数据导出到excel表格中 再下载下来 而生成Excel比较有名的框架有Apache poi等 网络上介绍其使用方法的文章也很多 但是我今天使用的是阿里出的easyexcel框架 我个人感觉使用起
  • mysql安装

    MySQL安装踩的坑 装MySQL卡了一天 一 卸载MySQL 先是文档安装路径里要删干净 C盘里看看有没有MySQL残留数据 3 控制面板 4 注册表 路径1 计算机 HKEY LOCAL MACHINE SYSTEM ControlSe
  • office2019选框虚线_Microsoft Office Visio如何绘制虚线?Microsoft Office Visio绘制虚线的方法步骤...

    Microsoft Office Visio如何绘制虚线 最近有很多小伙伴表示对于Microsoft Office Visio绘制虚线还不是很了解 那么今天的教程小编就给大家带来Microsoft Office Visio绘制虚线的方法步骤
  • 【C++】红黑树

    MarkDown输出x的平方和log以2为底的方法 1 x2 英文输入法 输入x 加 加 2 加 2 log2N 英文输入法 输入log 加 加 2 加 加 N 文章目录 1 红黑树概念 2 红黑树的性质 3 红黑树的实现 3 1 红黑树节