【C++、数据结构】手撕红黑树

news2024/9/22 23:27:47

文章目录

  • 📖 前言
  • 1. 红黑树的概念⚡
    • 🌀 1.2 红黑树的特性:
    • 🌀 1.3 与AVL树的相比:
  • 2. 结点的定义🌟
    • ⭐2.1 Key模型 和 Key_Value模型的引入:
        • 🏁2.1.1 K模型
        • 🏁2.1.2 KV模型
    • ⭐2.2 定义结点的代码:
  • 3. 结点的插入(重点)🔥
    • 💥3.1 新增结点颜色的选择:
    • 💥3.2具体插入流程:
        • 🏁情况一:(叔叔存在且为红)
        • 🏁情况二:(叔叔不存在 or 叔叔存在且为黑 — 单旋处理)
          • 具体情况 1
          • 具体情况 2
        • 🏁情况三:(叔叔不存在 or 叔叔存在且为黑 — 双旋处理)
    • 💥3.3 代码实现
  • 4. 验证红黑树⭕

📖 前言

本章我们将来介绍一下传说中的 “红黑树”

  • 在次之前我们学习了AVL树,AVL树是一棵二叉搜索树,通过平衡因子和旋转来保持整棵树的左右平衡。

同样红黑树也是一棵 “二叉搜索树”

  • AVL树相比只是规则不同,在实际的学习生活中用到的更多,接下来搬好小板凳准备开讲啦~~~ 🙋 🙋 🙋 🙋 🙋

前情回顾:AVL树复习 👉 传送门


1. 红黑树的概念⚡

概念:

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black,所以叫红黑树

通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
在这里插入图片描述

🌀 1.2 红黑树的特性:

红黑树一共有五大特性:

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

思考问题:

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

  • 最短: 全黑
  • 最长: 一黑一红间隔

红黑树是怎样实现 最长路径 <= 最短路径的两倍 呢?

  • 根据性质3可以知道红黑树没有连续的红结点
  • 根据性质4可以知道红黑树每条路径上的黑结点个数相同
    在这里插入图片描述

最短路径就是全是黑结点的情况,最长路径是一黑一红结点间隔排列的情况。

🌀 1.3 与AVL树的相比:

红黑树:

  • 红黑树也是二叉搜索树,只是换了一种思想
  • 间接控制了高度,在每个结点上增加了一个颜色,红色和黑色
  • 最长的路径不超过最短路径的2倍

AVL树:

  • AVL树是严格控制平衡,付出更多的代价去旋转
  • 红黑树则是放松了规则,不用很严格的平衡,近似平衡,最长路径不超过最短路径的2倍

单方面从查找来说:

AVL树查找的效率会更高,但是代价是AVL树插入时旋转了很多很多次才达到的平衡但是CPU足够的快,20次和40次差别不大。

综合来看:

红黑树跟胜一筹,在保证查找效率底线的同时,插入时旋转次数更少。


2. 结点的定义🌟

⭐2.1 Key模型 和 Key_Value模型的引入:

🏁2.1.1 K模型

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  • 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误

🏁2.1.2 KV模型

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见。

比如:英汉词典就是英文与中文的对应关系:

  • 通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对
  • 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对

⭐2.2 定义结点的代码:

我们还是实现的三叉链,颜色我们通过枚举类型来实现:

enum Colour
{
	RED,
	BLACK,
};

定义的节点如下:

template<class K, class V>
struct RBTreeNode
{
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;

	Colour _col;

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

这里结点一开始给红色的原因我们下文讲解。

3. 结点的插入(重点)🔥

💥3.1 新增结点颜色的选择:

为什么新增的结点要是红色的呢?

这里就要来解释一下为什么构造新的结点的时候为啥默认颜色要给红色的。

  • 我们这里如果新增的是黑结点的话,那么一定违反性质4(维护这棵树的时候其他支路的黑结点数量都要跟着改动,相当麻烦~)
  • 但是如果是新增的结点是红结点的话,那么如果被链接的那个结点是红色则违反性质3,如果被链接的那个结点是黑色的话则不违反性质3
  • 综上所述,新增Black结点一定违反性质4,新增Red结点不一定违反性质3

在这里插入图片描述

💥3.2具体插入流程:

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点。

这里用到的思路和AVL树用到的思路大致相同,都是不断地向上更新。

插入几大流程:

  1. 按照搜索二叉树的查找方法,找到要插入的位置
  2. 将新增结点插入到待插入位置
  3. 如果需要调整则调整红黑树

其中需不需要调整主要是看叔叔颜色的情况。

模型讲解:
在这里插入图片描述
和AVL树一样,三角形也是代表的是子树。

🏁情况一:(叔叔存在且为红)

  • cur为红,p为红,g为黑, u存在且为红

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

首先我们知道,红黑树调整主要看叔叔,第一步我们将父亲变成黑色,为了维护性质4,我们也要将叔叔的颜色变成黑色,同时也要将祖父结点的颜色变成红色,因为我们此时处理的不一定是整棵树,有可能是某个子树,如果此时不是子树,就需要将根节点变成黑色。

在这里插入图片描述
调整的部分可能是一整棵树,也可能是某一棵子树

  • 如果g是根节点,调整完成后,需要将g改为黑色
  • 如果g是子树,g一定有双亲,且g的双亲如果是红色,需要继续向上调整

在这里插入图片描述
情况一:不关心左右关系,只变色、不旋转,p、u是g的左和右是无所谓的,cur是p的左或者右也是一样的。

情况一的调整变化是为了变到其他的情况。


🏁情况二:(叔叔不存在 or 叔叔存在且为黑 — 单旋处理)

情况二可能就是从情况一调整变化得到的情况。

具体情况 1

当叔叔不存在时:
在这里插入图片描述
如图所示:如果单纯的按照情况一方式的调整的话,还是 违背了性质4,此时我们就想到了旋转的操作方式。
在这里插入图片描述

  • 此时是左边高了,我们对图示树进行右单旋,这里的旋转和AVL树中旋转的方式如出一辙,可以拿过来直接复用。
  • 同样的道理,如果是右边高了,我们就可以进行左单旋,旋转的方法也和AVL树中的如出一辙,也可拿过来直接复用。
具体情况 2

当叔叔存在且为黑时:

这种情况一定是由情况一变来的

解释:

我们用反证法,假设是在插入结点之前就有了情况二的样子

  • 假设是某一个棵树
  • n表示g结点所在支路之前黑结点的个数(不包括g)
  • m表示u结点所在支路之后黑结点的个数(不包括u)
    在这里插入图片描述
  • 如图所示很明显子树的根是g
  • g结点所在的左子树的支路黑结点个数为 n + 1
  • g结点所在的右子树的支路黑结点个数为 n + m + 2
  • 显然n + m + 2 > n + 1
  • 所以不可能在插入之前就会出现具体情况2的样子,已经违背红黑树的性质4
  • 综上所述,只要有可能是由情况一变来的

此时进行旋转 + 变色就能维护好红黑树的结构。
在这里插入图片描述

🏁情况三:(叔叔不存在 or 叔叔存在且为黑 — 双旋处理)

同样是 叔叔不存在 or 叔叔存在且为黑,为啥分为情况二和情况三呢?

上述旋转的情况都是单边的情况,也就是说,cur、p、g在一条线上的情况,若是出现了这三者不在一条直线的时候,单旋就解决不了问题了。

区别:

  • p是g的左,cur是p的左,那么是情况二 —— 单旋
  • p是g的左,cur是p的右,那么是情况三 —— 双旋

此时我们就引入了双旋
在这里插入图片描述

  • 先以p为旋转点再以g为旋转点
  • 先变到情况二的样子
  • 再根据情况二来继续变

此时有个疑问:情况二和情况三看样子都违背了红黑树的性质4,难道没错吗?

再此之前我们推测过当叔叔存在且为黑时,一定是由情况一变来的,所以cur一开始是黑的,这个树并不违反性质,子树由情况一变化之后的子树结点的颜色也相应变化了,只是没有显示出来而已。

💥3.3 代码实现

前序准备工作:
在这里插入图片描述
插入实现的代码:

bool Insert(const pair<K, V>& kv)
{
	//1、搜索树的规则插入
	//2、看是否违反平衡规则,如果违反就需要处理:旋转
	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->_right;
		}
		else if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			//不能数据重复
			return false;
		}
	}

	//找到符合规则的位置之后再插入
	cur = new Node(kv);
	cur->_col = RED;

	//真正的链接上
	if (parent->_kv.first < kv.first)
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}

	//三叉链的链接 -- 链上父节点
	cur->_parent = parent;

	//...

	//存在连续红色结点
	while (parent && parent->_col == RED)
	{
		//理论而言,祖父是一定存在的,父亲存在且是红不可能是根(根一定是黑的)
		Node* grandfather = parent->_parent;
		assert(grandfather);

		if (grandfather->_left == parent)
		{
			Node* uncle = grandfather->_right;
			//情况一:(叔叔存在且为红)
			if (uncle && uncle->_col == RED)
			{
				//父亲和叔叔变成黑色
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;

				//继续往上处理
				cur = grandfather;
				parent = cur->_parent;
			}
			//情况二:(叔叔不存在 or 叔叔存在且为黑)
			else if (uncle == nullptr || uncle->_col == BLACK)
			{
				//单旋
				//	   g
				//	 p
				// c
				if (cur == parent->_left)
				{
					RotateR(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				//双旋
				//    g
				//  p
				//    c
				else if (cur == parent->_right)
				{
					RotateL(parent);
					RotateR(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}

				break;
			}
		}
		//无论父亲和叔叔是左是右都是一样的
		//grandfather->_right == parent;
		else if(grandfather->_right == parent)
		{
			Node* uncle = grandfather->_left;
			//情况一:
			if (uncle && uncle->_col == RED)
			{
				//祖父和叔叔变成黑色
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;

				//继续往上处理
				cur = grandfather;
				parent = cur->_parent;
			}
			//情况二:(叔叔不存在 or 叔叔存在且为黑)
			else if (uncle == nullptr || uncle->_col == BLACK)
			{
				//单旋
				// g
				//   p
				//     c
				if (cur == parent->_right)
				{
					RotateL(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				//双旋
				//  g
				//    p
				//  c
				else if (cur == parent->_left)
				{
					RotateR(parent);
					RotateL(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}

				break;
			}
		}
	}

	//父亲为空就出循环,将根节点设置成黑色
	_root->_col = BLACK;

	return true;
}

旋转实现的代码:

//左旋
void RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;

	parent->_right = subRL;
	if (subRL)
	{
		subRL->_parent = parent;
	}

	Node* ppNode = parent->_parent;

	subR->_left = parent;
	parent->_parent = subR;

	if (parent == _root)
	{
		_root = subR;
		_root->_parent = nullptr;
	}
	else
	{
		if (parent == ppNode->_left)
		{
			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 (parent == _root)
	{
		_root = subL;
		_root->_parent = nullptr;
	}
	else
	{
		if (ppNode->_left == parent)
		{
			ppNode->_left = subL;
		}
		else
		{
			ppNode->_right = subL;
		}
		subL->_parent = ppNode;
	}

}

4. 验证红黑树⭕

我们通过一段代码来验证一下红黑树:

首先我们先将整个树遍历一遍来观察一下是否符合搜索二叉树:

中序遍历红黑树:

  • 同时我们再提供几个函数,用来求红黑树的高度和
//中序遍历
void InOrder()
{
	_InOrder(_root);
	cout << endl;
}

void _InOrder(Node* root)
{
	if (root == nullptr)
		return;

	_InOrder(root->_left);
	cout << root->_kv.first << " ";
	_InOrder(root->_right);
}

//求红黑树的最长路径
int _maxHeight(Node* root)
{
	if (root == nullptr)
		return 0;

	int lh = _maxHeight(root->_left);
	int rh = _maxHeight(root->_right);

	return lh > rh ? lh + 1 : rh + 1;
}

//求红黑树的最短路径
int _minHeight(Node* root)
{
	if (root == nullptr)
		return 0;

	int lh = _minHeight(root->_left);
	int rh = _minHeight(root->_right);

	return lh < rh ? lh + 1 : rh + 1;
}

void Height()
{
	cout << "最长路径:" << _maxHeight(_root) << endl;
	cout << "最短路径:" << _minHeight(_root) << endl;
}

//层序遍历
vector<vector<int>> levelOrder() 
{
	vector<vector<int>> vv;
	if (_root == nullptr)
		return vv;

	queue<Node*> q;
	int levelSize = 1;
	q.push(_root);

	while (!q.empty())
	{
		// levelSize控制一层一层出
		vector<int> levelV;
		while (levelSize--)
		{
			Node* front = q.front();
			q.pop();
			levelV.push_back(front->_kv.first);
			if (front->_left)
				q.push(front->_left);

			if (front->_right)
				q.push(front->_right);
		}
		vv.push_back(levelV);
		for (auto e : levelV)
		{
			cout << e << " ";
		}
		cout << endl;

		// 上一层出完,下一层就都进队列
		levelSize = q.size();
	}

	return vv;
}

测试1:

void TestRBTree1()
{
	//int a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	int a[] = { 30, 29, 28, 27, 26, 25, 24, 11, 8, 7, 6, 5, 4, 3, 2, 1 };
	RBTree<int, int> t;
	for (auto e : a)
	{
		t.Insert(make_pair(e, e));
	}
	t.levelOrder();
	t.InOrder();
	t.Height();
}

测试结果:
在这里插入图片描述
接下来我们通过红黑树的五大性质进行验证

//判断是否符合红黑树
bool IsBalanceTree()
{
	//检查红黑树几条规则

	Node* pRoot = _root;
	//空树也是红黑树
	if (nullptr == pRoot)
		return true;

	//检测根结点是否满足情况
	if (BLACK != pRoot->_col)
	{
		cout << "违反红黑树性质二:根节点必须为黑色" << endl;
		return false;
	}

	//获取任意一条路径中黑色节点的个数 -- 作为比较基准值
	size_t blackCount = 0;
	Node* pCur = pRoot;
	while (pCur)
	{
		if (BLACK == pCur->_col)
			blackCount++;

		pCur = pCur->_left;
	}

	//检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
	size_t k = 0;
	return _IsValidRBTree(pRoot, k, blackCount);
}

//上一个函数的返回值是调用这个函数
bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount)
{
	//走到nullptr之后,判断k和black是否相等
	if (nullptr == pRoot)
	{
		if (k != blackCount)
		{
			cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
			return false;
		}
		return true;
	}

	//统计黑色节点的个数
	if (BLACK == pRoot->_col)
		k++;

	//检测当前节点与其双亲是否都为红色
	if (RED == pRoot->_col && pRoot->_parent && pRoot->_parent->_col == RED)
	{
		cout << "违反性质三:存在连在一起的红色节点" << endl;
		return false;
	}

	return _IsValidRBTree(pRoot->_left, k, blackCount) &&
		_IsValidRBTree(pRoot->_right, k, blackCount);
}

通过递归的方式将每条支路都走了一遍和基准值比较,并且将红黑树的性质全都验证了。

测试2:

void TestRBTree2()
{
	const size_t N = 1024 * 1024 * 10;
	vector<int> v;
	v.reserve(N);
	srand(time(0));
	for (size_t i = 0; i < N; ++i)
	{
		//v.push_back(rand());
		v.push_back(i);
	}

	RBTree<int, int> t;
	for (auto e : v)
	{
		t.Insert(make_pair(e, e));
	}

	//t.levelOrder();
	//cout << endl;
	cout << "是否为红黑树?" << t.IsBalanceTree() << endl;
	t.Height();

	//t.InOrder();
}

测试结果:
在这里插入图片描述

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

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

相关文章

架构演进之路

架构设计: 一&#xff1a;如何分层。 1 为什么要分层&#xff1a;分而治之&#xff0c;各施其职&#xff0c;有条不紊。 常见的分层 计算机osi七层&#xff0c;mvc模型分层&#xff0c;领域模型分层。2 单系统分层模型演进 浏览器-->servlrt-->javabean-->db-->渲染…

unity组件LineRenderer

这是一个好玩的组件 主要作用划线&#xff0c;像水果忍者中的刀光&#xff0c;还有一些涂鸦的小游戏&#xff0c;包括让鼠标划线然后让对象进行跟踪导航也可通过此插件完成 附注&#xff1a;unity版本建议使用稳定一些的版本&#xff0c;有些api可能已经发生变化&#xff0c;…

【数据结构初阶】第四篇——双向链表

链表介绍 初始化链表 销毁链表 打印双向链表 查找数据 增加结点 头插 尾插 在指定位置插入 删除结点 头删 尾删 删除指定位置 链表判空 获取链表中元素个数 顺序表和链表对比 存取方式 逻辑结构与物理结构 时间性能 空间性能 链表介绍 本章讲的是带头双向链…

回溯算法秒杀所有排列-组合-子集问题

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛独家岛屿&#xff0c;本期将为大家揭晓LeetCode 78. 子集 90. 子集 II 77. 组合 39. 组合总和 40. 组合总和 II 47. 全排列 II&#xff0c;做好准备了么&#xff0c;那么开始吧。 &#x1f332;&#x1f…

上海亚商投顾:A股两市震荡走弱 北证50指数大涨5.8%

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪沪指今日震荡调整&#xff0c;创业板指午后一度跌近1.5%&#xff0c;黄白二线分化明显&#xff0c;题材概念表现活跃…

Redis快速入门

Redis快速入门&#xff0c;分两个客户端&#xff1a;Jedis和SpringDataRedis 使用Jdedis 1、引入依赖 <!--jedis--> <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version>…

python算法面试题

这是我年前做技术面试官&#xff0c;搜集的面试题&#xff0c;从python基础-机器学习-NLP-CV-深度学习框架-Linux-yolo都有一些题目。针对不同方向的应试者问相应方向的问题。 基本上都是面试八股文&#xff0c;收集记录一下&#xff0c;以后自己也会用的到。 面试题 python基…

深入理解mysql的内核查询成本计算

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…

过年回家,你是否也努力的给别人解释软件开发是干啥滴?

这个年就这样&#xff0c;在喜气洋洋的气氛中&#xff0c;在我们依依不舍的留恋中&#xff0c;从我们身边溜走了。这次回家又碰见了亲戚们不厌其烦的问我&#xff0c;你做什么工作呐&#xff1f;于是就有了我以下生动的解释 目录 打字的 帮助传话&#xff0c;帮助卖东西 皮…

易点易动打通固定资产采购,为企业实现降本增效

企业为什么要实现采购和资产管理的连接&#xff1f; 随着科技的发展&#xff0c;企业的办公工具越来越多&#xff0c;各类办公软件数不胜数。随之而来的是数据的不连通&#xff0c;员工需要穿梭在各个办公软件&#xff0c;重复导入导出数据&#xff0c;无形中没有提升办公效率…

三维电子沙盘数字沙盘开发教程第3课

三维电子沙盘数字沙盘开发教程第3课下面介绍矢量图层的控制显示&#xff1a;上代码foreach(string key in gis3d.SetFile.Biao.Keys)// gis3d.SetFile.Biao 该对象里存储了所有矢量层的信息{gis3d.SetFile.Biao[key].Show true; //是否显示标签gis3d.SetFile.Biao[key].ShowTe…

1.Weisfeiler-Lehman Algorithm

文章目录1.图同构介绍2.Weisfeiler-Lehman Algorithm3.后话参考资料欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; Weisfeiler-Lehman Algorithm是美国的数学家Boris Weisfeiler在1968年发表的论文the reduction of a graph to a canonic…

Flask WebSocket学习笔记

WebSocket简介&#xff1a;WebSocket是一种全新的协议&#xff0c;随着HTML5的不断完善&#xff0c;越来越多的现代浏览器开始全面支持WebSocket技术了&#xff0c;它将TCP的Socket&#xff08;套接字&#xff09;应用在了webpage上&#xff0c;从而使通信双方建立起一个保持在…

Java面向对象基础

文章目录面向对象一、类和对象1. 类的介绍2. 类和对象的关系3. 类的组成4. 创建对象和使用对象的格式二、对象内存图1. 单个对象内存图2. 两个对象内存图3. 两个引用指向相同内存图三、成员变量和局部变量四、this 关键字1. this 可以解决的问题2. this 介绍3. this 内存图五、…

学术的快乐来源

文章目录我的核心快乐来源&#xff1a;其他非核心快乐源泉知乎搜到的别人的快乐来源作此文&#xff0c;以便懈怠时候看看&#xff0c;能够聊表安慰。 ——题记 抱着给自己枯燥无聊学术生涯找点乐子的想法&#xff0c; 我决定仔细思考一下自己做学术的时候有哪些快乐的地方&…

C++关于开源包7zip压缩工具的编译及使用

1、7zip的配置 7-Zip是一款免费开源的压缩与解压软件&#xff0c;基本能够满足绝大多数常见的压缩和解压文件需求&#xff0c;此外还支持了分卷压缩和解压&#xff0c;非常好用。但是调用7-zip库需要用到一个叫bit7z的库&#xff0c;bit7z是一个C静态库&#xff0c;其封装了简单…

MySQL 中主从之间是怎样保证数据一致的呢?

在我们日常的工作中&#xff0c;处理 MySQL 数据库相关问题时&#xff0c;我相信绝大多数 DBA 处理最棘手的问题就是数据库主从数据不一致的问题。 处理过关于 MySQL 数据库主从数据不一致的朋友一定印象非常深刻&#xff0c;因为稍有不慎就会将造成原有数据的丢失&#xff0c…

精益安灯电子看板实现了实时监测

众所周知&#xff0c;智能工厂的规划建设是一个十分复杂的系统工程。所以安灯电子看板是精益生产中一一个重要组成要素&#xff0c;可以提升工厂生产车间的过程管理&#xff0c;生产数据做的信息化、目视化&#xff1b;信息快捷化、生产工序透明化等&#xff0c;是提高生产率的…

自动控制原理笔记-根轨迹的概念-根轨迹方程

目录 根轨迹的基本概念&#xff1a; 根轨迹的概念&#xff1a;当开环系统某一参数从 0 到∞变化时&#xff0c;闭环极点在S 平面上变化所描绘出的轨迹。 闭环零极点与开环零极点之间的关系&#xff1a; 根轨迹方程&#xff1a; 开环增益于根轨迹间的关系&#xff1a; 闭环系…

excel 格式化日期为字符串

最近经常遇到excel打开文件的时候&#xff0c;excel自动将yyyy-MM-dd HH:mm:ss &#xff08;如&#xff1a;2022-01-21 12:12:12 &#xff09;之类的时间的自动转为这样的格式列&#xff0c;2022/1/21 12:12:12 &#xff0c;导致有想从excel/csv格式 中复制原始日期格式比较麻烦…