【c++】【数据结构】红黑树

news2025/6/4 15:38:29

目录

  • 红黑树的定义
  • 红黑树的部分模拟实现
    • 颜色的向上更新
    • 旋转算法
      • 单旋算法
      • 双旋算法
  • 红黑树与AVL树的对比

红黑树的定义

红黑树是一种自平衡的二叉搜索树,通过特定的规则维持树的平衡。红黑树在每个结点上都增加一个存储位表示结点的颜色,结点的颜色可以是红色或者黑色,然后做出一下规定:

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

通过这五条规则的限制,红黑树就可以保证树中没有一条路径会比其他路径的两倍还长,红黑树将这种状态视为为平衡。为什么通过这几条规则就能做到呢?其重点在于规则4,即对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点,这样的话不难想到,最短路径的情况就是一条路径上面全是黑色结点;而通过规则3我们可以知道,一条路径上的红节点是不能连续存在的,又因为规则4的限制,我们要想让一条路径尽可能地长就只有往黑节点的间隙插入红节点,但是红节点不能连续,所以就是一个黑节点接一个红结点。最短路径是全黑,最长路径是一个黑接一个红,不难想象,最长路径不会超过最短路径的两倍,最多也就是两倍。

红黑树的部分模拟实现

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>

using namespace std;

enum Color
{
	red,
	black
};

template<class Key, class Value>
struct RB_Node
{
	typedef RB_Node<Key, Value> Node;

	RB_Node(Key k, Value v, Color c) :
		_key(k),
		_value(v),
		_color(c)
	{
	}

	Node* _parent = nullptr;
	Node* _left = nullptr;
	Node* _right = nullptr;

	Key _key = 0;
	Value _value = 0;

	Color _color = red;
};

template<class Key, class Value>
class RB_Tree
{
public:
	int rotation_num = 0;

	typedef RB_Node<Key, Value> Node;

	bool insert(Key k, Value v)
	{
		if (!_root)
		{
			_root = new Node(k, v, black);
			return true;
		}

		Node* cur = _root;
		Node* parent = nullptr;

		while (cur)
		{
			if (cur->_key == k) return false;

			parent = cur;
			if (cur->_key > k) cur = cur->_left;
			else cur = cur->_right;
		}

		cur = new Node(k, v, red);
		if (parent->_key > cur->_key)
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_right = cur;
			cur->_parent = parent;
		}

		while (parent)
		{
			if (parent->_color == black) break;

			Node* pparent = parent->_parent;
			Node* uncle = nullptr;
			if (pparent->_key > parent->_key) uncle = pparent->_right;
			else uncle = pparent->_left;

			if (!uncle || uncle->_color == black)
			{
				if (pparent->_key > parent->_key)
				{
					if (parent->_key > cur->_key)
					{
						Rrotation(parent);
						parent->_color = black;
						pparent->_color = red;
					}
					else
					{
						LRrotation(parent);
						cur->_color = black;
						pparent->_color = red;
					}
				}
				else
				{
					if (parent->_key < cur->_key)
					{
						Lrotation(parent);
						parent->_color = black;
						pparent->_color = red;
					}
					else
					{
						RLrotation(parent);
						cur->_color = black;
						pparent->_color = red;
					}
				}
				if (parent == _root) parent->_color = black;
				break;
			}
			else if (uncle->_color == red)
			{
				uncle->_color = parent->_color = black;
				pparent->_color = red;

				if (pparent == _root)
				{
					pparent->_color = black;
					break;
				}
				cur = pparent;
				parent = pparent->_parent;
			}
		}
		return true;
	}

	//void inorder()//中序打印
	//{
	//	_inorder(root);
	//}

	//int high()//树的高度
	//{
	//	return _high(root);
	//}

	//void check()//检查结点平衡
	//{
	//	_check(root);
	//}

	bool CheckColour(Node* root, int blacknum, int benchmark)
	{
		if (root == nullptr)
		{
			if (blacknum != benchmark)
				return false;

			return true;
		}

		if (root->_color == black)
		{
			++blacknum;
		}

		if (root->_color == red && root->_parent && root->_parent->_color == red)
		{
			cout << root->_key << "出现连续红色节点" << endl;
			return false;
		}

		return CheckColour(root->_left, blacknum, benchmark)
			&& CheckColour(root->_right, blacknum, benchmark);
	}

	bool IsBalance()
	{
		return IsBalance(_root);
	}

	bool IsBalance(Node* root)
	{
		if (root == nullptr)
			return true;

		if (root->_color != black)
		{
			return false;
		}

		// 基准值
		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_color == black)
				++benchmark;

			cur = cur->_left;
		}

		return CheckColour(root, 0, benchmark);
	}

	int Height()
	{
		return Height(_root);
	}

	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;
	}

private:
	//int _check(Node* cur)
	//{
	//	if (!cur) return 0;
	//	int lret = _check(cur->_left);
	//	int rret = _check(cur->_right);
	//	if (lret != rret) cout << cur->_key << " : 错误" << endl;
	//	if (cur->_color == black) return lret + 1;
	//	return lret;
	//}

	//int _high(Node* cur)
	//{
	//	if (!cur) return 0;
	//	int releft = _high(cur->_left);
	//	int reright = _high(cur->_right);
	//	return releft > reright ? releft + 1 : reright + 1;
	//}

	//void _inorder(Node* cur)
	//{
	//	if (!cur) return;
	//	_inorder(cur->_left);
	//	cout << cur->_key << endl;
	//	_inorder(cur->_right);
	//}

	void LRrotation(Node* cur)
	{
		Lrotation(cur->_right);
		cur = cur->_parent;
		Rrotation(cur);
	}

	void RLrotation(Node* cur)
	{
		Rrotation(cur->_left);
		cur = cur->_parent;
		Lrotation(cur);
	}

	void Lrotation(Node* cur)
	{
		rotation_num++;
		Node* parent = cur->_parent;
		Node* pparent = parent->_parent;
		Node* cur_left = cur->_left;

		parent->_right = cur_left; //左右节点更新
		cur->_left = parent;

		if (cur_left) cur_left->_parent = parent; //父节点的更新
		parent->_parent = cur;
		cur->_parent = pparent;

		if (pparent) //判断是不是空
		{
			if (pparent->_key > cur->_key) pparent->_left = cur; //父节点的父节点更新
			else pparent->_right = cur;
		}
		else
		{
			_root = cur;
			cur->_parent = nullptr; //解耦
		}

		//cur->_color = black; //颜色更新
		//parent->_color = red;
	}

	void Rrotation(Node* cur)
	{
		rotation_num++;
		Node* parent = cur->_parent;
		Node* pparent = parent->_parent;
		//Node* son = cur->_left;
		Node* cur_right = cur->_right;

		parent->_left = cur_right; //左右节点更新
		cur->_right = parent;

		if (cur_right) cur_right->_parent = parent; //父节点的更新
		parent->_parent = cur;
		cur->_parent = pparent;

		if (pparent) //判断是不是空
		{
			if (pparent->_key > cur->_key) pparent->_left = cur; //父节点的父节点更新
			else pparent->_right = cur;
		}
		else
		{
			_root = cur;
			cur->_parent = nullptr; //解耦
		}

		//cur->_color = black; //颜色更新
		//parent->_color = red;
	}

	Node* _root = nullptr;
};

对于红黑树来说,其最核心的无疑就是插入和删除函数,这里笔者能力有限,只实现了插入函数。

首先搞个枚举定义红跟黑两种状态,在结点中引入颜色变量,颜色默认为红色。因为要维持对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点 ,所以黑色节点是不会轻易添加的,默认就是添加红结点。

颜色的向上更新

插入函数的插入逻辑的实现与普通二叉搜索树无异,这里不过多赘述,这里重点讲讲颜色的更新方式。首先我们看向下面这张图,
在这里插入图片描述
在这里插入图片描述
我们在插入红结点时,会遇到这两种情况,一种是父结点为红色,一种是父结点为黑色。当父结点为黑色时,红节点的插入不会破坏任何规则,当父结点为红色时,红结点的插入会破坏如果一个节点是红色的,则它的两个孩子结点是黑色的规则,这时我们应该怎么办呢?把父结点或者子结点的颜色变成黑色吗?不行,因为要维持对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点的规则,擅自增加黑结点会破坏这种规则,那应该怎么办呢?我们看向下面这张图,
在这里插入图片描述
方块就是结点连接的子树,这样这张图就能代表更为普遍的情况。可以看到,当出现连续红结点冲突时,我们应该将父结点与叔叔结点一起变成黑色,再将爷爷结点变成红色,之后我们应该看向爷爷结点的父结点,如果又出现了连续红结点,就应该继续这个过程,向上更新颜色。

上面讲的这种情况是在叔叔结点为红的情况下的做法,但是叔叔结点也可能为黑或者直接不存在,这时就没法直接用变色的套路了。AVL树中我们遇到平衡因子为2或-2时,就表示树不平衡了,需要使用旋转函数,这里也是如此,当父结点为红而叔叔结点为黑或不存在时,就表明父结点所在的子树的高度大于叔叔结点所在子树的高度,因为父结点所在的子树红节点更多,而且由于是一路向上变色而来的,父结点所在的子树就是一红一黑这种最长的排法,所以可以认为此时的红黑树已经是一种不平衡的状态了,以至于无法正常向上变色了,这时我们采取和AVL树一样的做法,那就是动用旋转算法。

旋转算法

单旋算法

红黑树的旋转算法与AVL树的一模一样,但是AVL需要在旋转后改变平衡因子,而红黑树则需要改变结点的颜色,更新策略如下,
在这里插入图片描述
这是叔叔结点为黑的情况,如果叔叔节点不存在,根据红黑树的性质,则一定是下面这个样子,
在这里插入图片描述
son一定是新插入的结点,这种情况可以与叔叔节点为黑的情况一起处理,都是通用的。当然我这里举例的都是左子树高的情况,把我画的图镜像过来就是右子树高的情况。对于左子树高的情况我们用右旋,右子树高的情况我们用左旋,与AVL树一致,旋转的思路我在介绍AVL树的文章中写过了,这里不过多赘述,直接上代码,

	void Lrotation(Node* cur) //左单旋
	{
		rotation_num++;
		Node* parent = cur->_parent;
		Node* pparent = parent->_parent;
		Node* cur_left = cur->_left;

		parent->_right = cur_left; //左右节点更新
		cur->_left = parent;

		if (cur_left) cur_left->_parent = parent; //父节点的更新
		parent->_parent = cur;
		cur->_parent = pparent;

		if (pparent) //判断是不是空
		{
			if (pparent->_key > cur->_key) pparent->_left = cur; //父节点的父节点更新
			else pparent->_right = cur;
		}
		else
		{
			_root = cur; //更新根结点
			cur->_parent = nullptr; //解耦
		}

		//cur->_color = black; //颜色更新
		//parent->_color = red;
	}

	void Rrotation(Node* cur) //右单旋
	{
		rotation_num++;
		Node* parent = cur->_parent;
		Node* pparent = parent->_parent;
		//Node* son = cur->_left;
		Node* cur_right = cur->_right;

		parent->_left = cur_right; //左右节点更新
		cur->_right = parent;

		if (cur_right) cur_right->_parent = parent; //父节点的更新
		parent->_parent = cur;
		cur->_parent = pparent;

		if (pparent) //判断是不是空
		{
			if (pparent->_key > cur->_key) pparent->_left = cur; //父节点的父节点更新
			else pparent->_right = cur;
		}
		else
		{
			_root = cur;
			cur->_parent = nullptr; //解耦
		}

		//cur->_color = black; //颜色更新
		//parent->_color = red;
	}

双旋算法

AVL树中出现折线形时使用单旋函数就不管用了,对于红黑树也是一样,
在这里插入图片描述
使用单旋同样就不管用了,
在这里插入图片描述
需要使用双旋来解决问题,
在这里插入图片描述
双旋算法的思路与AVL也是一致的,这里不过多赘述,双旋完之后注意变色就行,这里因为son结点变成了黑色,所以同样不需要再向上变色了。

	void LRrotation(Node* cur)
	{
		Lrotation(cur->_right);
		cur = cur->_parent;
		Rrotation(cur);
	}

	void RLrotation(Node* cur)
	{
		Rrotation(cur->_left);
		cur = cur->_parent;
		Lrotation(cur);
	}

这样insert函数就完成了,

bool insert(Key k, Value v)
{
	if (!_root)
	{
		_root = new Node(k, v, black);
		return true;
	}

	Node* cur = _root;
	Node* parent = nullptr;

	while (cur)
	{
		if (cur->_key == k) return false;

		parent = cur;
		if (cur->_key > k) cur = cur->_left;
		else cur = cur->_right;
	}

	cur = new Node(k, v, red);
	if (parent->_key > cur->_key)
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	else
	{
		parent->_right = cur;
		cur->_parent = parent;
	}

	while (parent)
	{
		if (parent->_color == black) break;

		Node* pparent = parent->_parent;
		Node* uncle = nullptr;
		if (pparent->_key > parent->_key) uncle = pparent->_right;
		else uncle = pparent->_left;

		if (!uncle || uncle->_color == black)
		{
			if (pparent->_key > parent->_key)
			{
				if (parent->_key > cur->_key)
				{
					Rrotation(parent);
					parent->_color = black;
					pparent->_color = red;
				}
				else
				{
					LRrotation(parent);
					cur->_color = black;
					pparent->_color = red;
				}
			}
			else
			{
				if (parent->_key < cur->_key)
				{
					Lrotation(parent);
					parent->_color = black;
					pparent->_color = red;
				}
				else
				{
					RLrotation(parent);
					cur->_color = black;
					pparent->_color = red;
				}
			}
			if (parent == _root) parent->_color = black;
			break;
		}
		else if (uncle->_color == red)
		{
			uncle->_color = parent->_color = black;
			pparent->_color = red;

			if (pparent == _root)
			{
				pparent->_color = black;
				break;
			}
			cur = pparent;
			parent = pparent->_parent;
		}
	}
	return true;
}

除了插入函数之外,我还写了一些其他的函数来测试插入函数的正确与否,大家可以用作参考,实现思路较为简单,不做过多赘述。

红黑树与AVL树的对比

红黑树与AVL树都属于自平衡的二叉搜索树,两者都有自己的一套维护手段,但对于平衡的维护方面,红黑树允许最长路径达到最短路径的两倍,而AVL只允许两子树的高度差最多为1,所以AVL毫无疑问在维护平衡方面是比红黑树严格得多的,所以我们可以预见在相同一组随机数据(得足够多,太少可能看不出差异)插入后AVL树一定排的比红黑要满,AVL树的高度也一定比红黑树要低,所以AVL树在插入后的查找效率是比红黑略高的,但是,我们应该明白为了这点查找效率AVL树付出了多少代价,我这里写了一组测试函数,用我写的红黑与AVL放进来测试,我在AVL和红黑中都放了有个记录旋转次数的变量,每调用一次旋转函数,就++这个变量,又写了一个函数递归计算树的高度,

void test()
{
	RB_Tree<int, int> x;
	AVL_Tree<int, int> y;
	for (int i = 0; i < 10000000; ++i)
	{
		int tmp = rand() % 10000000 + i;
		x.insert(tmp, 0);
		y.insert(tmp, 0);
	}

	cout << "RB : " << "旋转次数 : " << x.rotation_num << " 高度 : " << x.Height() << endl;
	cout << "AVL : " << "旋转次数 : " << y.rotation_num << " 高度 : " << y.high() << endl;
}

int main()
{
	srand(time(NULL));

	test();
	return 0;
}

我这里用了一组十分可观的数据量,跑出来的结果是,
在这里插入图片描述
我们可以看到红黑树的高度比AVL大了7,但是红黑树比AVL少旋转了约74万次,计算机多查找7层眨眼间的工夫就能完成,但多旋转74万次计算机可就要跑好一会了。所以我们可以明白,除非需要极其频繁的查找或需要极致的查找效率,不然AVL为了那点查找效率所付出的代价是得不偿失的。事实上,在实际运用中,红黑的实用性也是远远大于AVL,c++中set和map的底层用的就是红黑而不是AVL,java中的TreeMap也是如此。

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

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

相关文章

基于SpringBoot+Redis实现RabbitMQ幂等性设计,解决MQ重复消费问题

解决MQ重复消费问题 一、实现方案 本方案参考 「RabbitMQ消息可靠性深度解析&#xff5c;从零构建高可靠消息系统的实战指南」&#xff0c;向开源致敬&#xff01; 1、业务层幂等处理&#xff1a; 每个消息携带一个全局唯一ID&#xff0c;在业务处理过程中&#xff0c;首先检查…

使用lighttpd和开发板进行交互

文章目录 &#x1f9e0; 一、Lighttpd 与开发板的交互原理1. 什么是 Lighttpd&#xff1f;2. 与开发板交互的方式&#xff1f; &#x1f9fe; 二、lighttpd.conf 配置文件讲解⚠️ 注意事项&#xff1a; &#x1f4c1; 三、目录结构说明&#x1f4a1; 四、使用 C 编写 CGI 脚本…

DRF的使用

1. DRF概述 DRF即django rest framework&#xff0c;是一个基于Django的Web API框架&#xff0c;专门用于构建RESTful API接口。DRF的核心特点包括&#xff1a; 序列化&#xff1a;通过序列化工具&#xff0c;DRF能够轻松地将Django模型转换为JSON格式&#xff0c;也可以将JS…

2024年09月 C/C++(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:有几个PAT 字符串 APPAPT 中包含了两个单词 PAT,其中第一个 PAT 是第 2 位,第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位,第 4 位(A),第 6 位(T)。 现给定字符串,问一共可以形成多少个 PAT? 时间限制:1000 内存限制:26214…

免费且好用的PDF水印添加工具

软件介绍 琥珀扫描.zip下载链接&#xff1a;https://pan.quark.cn/s/3a8f432b29aa 今天要给大家推荐一款超实用的PDF添加水印工具&#xff0c;它能够满足用户给PDF文件添加水印的需求&#xff0c;而且完全免费。 这款PDF添加水印的软件有着简洁的界面&#xff0c;操作简便&a…

mqtt协议连接阿里云平台

首先现在的阿里云物联网平台已经不在新购了&#xff0c;如下图所示&#xff1a; 解决办法&#xff1a;在咸鱼上租用一个账号&#xff0c;先用起来。 搭建阿里云平台&#xff0c;参考博客&#xff1a; &#xff08;一&#xff09;MQTT连接阿里云物联网平台&#xff08;小白向&…

一文详谈Linux中的时间管理和定时器编程

&#xff08;目录&#xff09; 先说一些在计算机中需要用到时间的地方&#xff1a;系统日志log、OS调度(时间片、定时器)等等~~ 时间的计量 计时的方式发展&#xff1a;日晷、沙漏 -> 机械钟 -> 石英振荡器、晶振 -> 铯原子钟 -> 氢原子钟 计算机中的计时方式&…

性能优化 - 理论篇:常见指标及切入点

文章目录 引言一、 Java 性能优化的核心思路二、为什么要度量&#xff1f;三、常用性能衡量指标详解3.1 吞吐量与响应速度3.2 响应时间的具体度量&#xff1a;平均响应时间与百分位数3.3 并发量3.4 秒开率&#xff08;页面秒开&#xff09;3.5 正确性&#xff08;功能可用性&am…

【论文阅读 | PR 2024 |ICAFusion:迭代交叉注意力引导的多光谱目标检测特征融合】

论文阅读 | PR 2024 |ICAFusion&#xff1a;迭代交叉注意力引导的多光谱目标检测特征融合 1.摘要&&引言2.方法2.1 架构2.2 双模态特征融合&#xff08;DMFF&#xff09;2.2.1 跨模态特征增强&#xff08;CFE&#xff09;2.2.2 空间特征压缩&#xff08;SFS&#xff09;…

华为OD机试真题——模拟消息队列(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《模拟消息队列》: 目录 题…

MySql(十三)

目录 mysql外键约束 准备工作 创建表 插入数据 创建表时添加外键 1..格式 2..创建表student表时&#xff0c;为其添加外键 3.插入数据测试 正常数据 异常数据 3.使用alter添加外键 删除外键 添加外键 4.Mysql外键不生效的原因 修改引擎 phpystudy的mysql位置 mysql外键约束 注&…

iOS —— UI 初探

简介 第一次新建时&#xff0c;你可能会好奇。为什么有这么多文件&#xff0c;他们都有什么用&#xff1f; App 启动与生命周期管理相关 文件名 类型 作用 main.m m 程序入口&#xff0c;main() 函数定义在这里 AppDelegate.h/.m h/m App 启动/进入后台/退出等全局事…

day23-计算机网络-1

1. 网络简介 1.1. 网络介质 网线&#xff1a;cat5,cat5e 六类网线&#xff0c;七类网线&#xff0c;芭蕾网线光纤&#xff1a;wifi&#xff1a;无线路由器&#xff0c;ap5G 1.2. 常见网线类型 1.2.1. 双绞线&#xff08;Twisted Pair Cable&#xff09;【最常用】 按性能主…

C语言基础(09)【数组的概念 与一维数组】

数组 数组的概念 什么是数组 数组是相同类型、有序数据的集合。 数组的特征 数组中的数据称之为数组的元素(数组中的每一个匿名变量空间&#xff0c;是同构的)数组中的元素存放在内存空间建立。 衍生概念&#xff1a;下标&#xff08;索引&#xff09; 下标或者索引代表…

【JavaScript】Ajax 侠客行:axios 轻功穿梭服务器间

一、AJAX 概念和 axios 使用讲解 什么是 AJAX ? 使用浏览器的 XMLHttpRequest 对象与服务器通信 浏览器网页中&#xff0c;使用 AJAX技术&#xff08;XHR对象&#xff09;发起获取省份列表数据的请求&#xff0c;服务器代码响应准备好的省份列表数据给前端&#xff0c;前端…

Django数据库连接报错 django.db.utils.NotSupportedError: MySQL 8 or later is required

可尝试换django版本 pip install django3.2.13 另外mysql下载地址 https://dev.mysql.com/downloads/installer/ 安装可以参考&#xff1a; https://blog.csdn.net/HHHQHHHQ/article/details/148125549 重点&#xff1a;用户变量添加 C:\Program Files\MySQL\MySQL Server …

2025年- H57-Lc165--994.腐烂的橘子(图论,广搜)--Java版

1.题目描述 2.思路 3.代码实现 import java.util.LinkedList; import java.util.Queue;public class H994 {public int orangesRotting(int[][] grid) {//1.获取行数int rowsgrid.length;int colsgrid[0].length;//2.创建队列用于bfsQueue<int[]> quenew LinkedList<…

(9)-Fiddler抓包-Fiddler如何设置捕获Https会话

1.简介 由于近几年来各大网站越来越注重安全性都改成了https协议&#xff0c;不像前十几年前直接是http协议直接裸奔在互联网。接着讲解如何抓取https协议会话。 2.什么是HTTPS&#xff1f; HTTPS就是加过密的HTTP。使用HTTPS后&#xff0c;浏览器客户端和Web服务器传输的数…

Vue-Router 基础使用

Vue Router 是 Vue 官方的客户端路由解决方案。 客户端路由的作用是在单页应用 SPA 中将浏览器的 URL 和用户看到的内容绑定起来。当用户在应用中浏览不同页面时&#xff0c;URL 会随之更新&#xff0c;但页面不需要从服务器重新加载。 Vue Router 基于 Vue 的组件系统构建&a…

【案例分享】蓝牙红外线影音遥控键盘:瑞昱RTL8752CJF

蓝牙红外线影音遥控键盘 Remotec的无线控制键盘采用瑞昱蓝牙RTL8752CJF解决方案&#xff0c;透过蓝牙5.0与手机配对后&#xff0c;连线至 Remotec 红外 code server 取得对应影音视觉设备的红外 code后&#xff0c;即可控制多达2个以上的影音视觉设备&#xff0c;像是智能电视…