红黑树(万字图文详解)

news2024/11/24 5:30:59

红黑树

  • 1. 红黑树的概念
  • 2. 红黑树的性质
  • 3. 红黑树节点的定义
  • 4. 红黑树结构
  • 5. 红黑树的插入操作
    • 5.1 按照二叉搜索的树规则插入新节点
    • 5.2 检测新节点插入后,红黑树的性质是否造到破坏
      • 5.2.1 情况一: cur为红,p为红,g为黑,u存在且为红
      • 5.2.2 情况二: cur为红(此时只需要单旋),p为红,g为黑,u不存在/u存在且为黑
      • 5.2.3 情况三: cur为红(此时需要进行双旋变成情况二),p为红,g为黑,u不存在/u存在且为黑
  • 完整代码
  • 6. 红黑树的验证
    • 1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)
    • 2. 检测其是否满足红黑树的性质
  • 7. 红黑树与AVL树的比较
  • 8. 红黑树的应用

注:本文的是在理解AVL树的基础上进行讲解的!


AVL树的实现(万字图文详解)


1. 红黑树的概念

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

2. 红黑树的性质

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

在这里插入图片描述

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

  1. 红黑树中的性质确保了任意路径上的黑色节点数量相等,这是红黑树能够保持平衡的关键。根据这个性质,我们可以证明红黑树的最长路径中的节点个数不会超过最短路径的节点个数的两倍。
  2. 假设红黑树的最短路径上的黑色节点数量为k。由于性质5,任意路径上的黑色节点数量相等,所以最长路径上的黑色节点数量不能少于k个。
  3. 现在我们来看最长路径上的节点个数。由于性质4,红色节点的两个子节点都是黑色的,因此最长路径上不能有连续的红色节点。而对于红黑树而言,最长路径上的红色节点数量最多为k,因为最长路径上的黑色节点数量不能少于k个。所以最长路径上的节点个数最多为2k,其中k个是黑色节点,k个是红色节点。
  4. 综上所述,红黑树的最长路径中的节点个数不会超过最短路径的节点个数的两倍,即最长路径上的节点个数最多为2k,其中k为最短路径上的黑色节点数量
  5. 这个性质保证了红黑树的高度始终保持在较小的范围内,从而保持了树的平衡性。因为红黑树的高度与最长路径上的节点个数成正比,所以最长路径的节点个数的上限为最短路径的节点个数的两倍,确保了红黑树的平衡性和高效性。

3. 红黑树节点的定义

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;
	int _bf;
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)//左孩子
		, _right(nullptr)//右孩子
		, _parent(nullptr)//父亲
		, _kv(kv)//存储键值对的成员变量
		, _col(RED)//默认红色
	{}
};

具体解释如下:

  • _left:指向左子节点的指针。
  • _right:指向右子节点的指针。
  • _parent:指向父节点的指针。
  • _kv:存储键值对的成员变量。这里使用了 pair<K, V> 类型来表示键值对,其中 K 是键的类型,V 是值的类型。
  • _col:表示节点的颜色。这里使用了 Colour 枚举类型来表示,可能的取值为 RED 或 BLACK,其中 RED 表示红色,BLACK 表示黑色。
  • _bf:平衡因子,用于平衡二叉树的调整。

4. 红黑树结构

为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为根节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点
如下:
在这里插入图片描述

5. 红黑树的插入操作

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

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

#pragma once
#include <iostream>
using namespace std;

//枚举类型变量
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;
	int _bf;
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _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)
		{
			_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;
				cur->_parent = parent;
			}
			else
			{
				parent->_left = cur;
				cur->_parent = parent;
			}

			
			红黑树开整
			//1.cur为红,parent为红,grandfather为黑,uncle存在且为红
			//解决方法:p,u变成黑,g变成红,c=g,继续向上调整
			//2.cur为红,parent为红,grandfather为黑,uncle不存在 or 存在且为黑
			//解决方法: 单旋:p变红,g变黑,//双旋:c变黑,g变红

private:
	Node* _root = nullptr;
};

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

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

在这里插入图片描述
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

5.2.1 情况一: cur为红,p为红,g为黑,u存在且为红

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

在这里插入图片描述

5.2.2 情况二: cur为红(此时只需要单旋),p为红,g为黑,u不存在/u存在且为黑

在这里插入图片描述

在这里插入图片描述
解决方法:

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

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


5.2.3 情况三: cur为红(此时需要进行双旋变成情况二),p为红,g为黑,u不存在/u存在且为黑

在这里插入图片描述
解决方法:

  • p为g的左孩子,cur为p的右孩子,则针对p做左单旋转,再对g右单旋即可完成调整;
  • 相反,
    p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
    ,再对g左单旋即可完成调整

在这里插入图片描述


在这里插入图片描述

完整代码

#pragma once
#include <iostream>
using namespace std;

//枚举类型变量
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;
	int _bf;
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _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)
		{
			_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;
				cur->_parent = parent;
			}
			else
			{
				parent->_left = cur;
				cur->_parent = parent;
			}

			
			红黑树开整
			//1.cur为红,parent为红,grandfather为黑,uncle存在且为红
			//解决方法:p,u变成黑,g变成红,c=g,继续向上调整
			//2.cur为红,parent为红,grandfather为黑,uncle不存在 or 存在且为黑
			//解决方法: 单旋:p变红,g变黑,//双旋:c变黑,g变红



			//parent不为空,且parent->_col==RED(这样保证肯定有祖先,也就是grandfather不为空)
			while (parent && parent->_col == RED)
			{
				//    g
				//  p   u
				//c
				Node* grandfather = parent->_parent;
				if (parent == grandfather->_left)
				{
					//    g
				    //  p   u
				    //c
					Node* uncle = grandfather->_right;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandfather->_col = RED;
						
						//继续往上更新处理
						cur = grandfather;
						parent = cur->_parent;//这儿parent更新完之后可能为空,为空就结束
					}
					else//uncle不存在 or 存在且为黑
					{   //单旋
						//    g
					    //  p   u
					    //c
						if (cur == parent->_left)
						{
							RotateR(grandfather);
							parent->_col = BLACK;//p变黑
							grandfather->_col = RED;//g变红
						}
						else if (cur == parent->_right)
						{
							//双旋
							//    g
							//  p   u
							//    c
							RotateL(parent);
							RotateR(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}

						break;
					}
					
				}
				//    g
				//  u   p
				//        c
				else//  parent == grandfather->_left
				{
					Node* uncle = grandfather->_left;
					if (uncle && uncle->_col == RED)
					{
						parent->_col = uncle->_col = BLACK;
						grandfather->_col = RED;

						//继续往上更新处理
						cur = grandfather;
						parent = cur->_parent;
					}

					else//(uncle不存在 or 存在且为黑)
					{   //单旋
						//    g         
						//  u   p           
						//        c    
						if (cur == parent->_right)
						{
							RotateL(grandfather);
							parent->_col = BLACK;//p变黑
							grandfather->_col = RED;//g变红
						}	
						else//cur == parent->_left 
						{
							//双旋
							//    g
							//  u   p
							//    c  
							RotateR(parent);
							RotateL(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}

			}
			//管你根节点更新成啥了,管你个求,直接把_root->_col改成黑色
			_root->_col = BLACK;
		return true;
	}



	//左单旋
	//(1.父亲节点的右边等于右孩子的左边; 2.右孩子的左边等于父亲节点)
	//【把右孩子的左边给给父亲节点的右边; 2.再把父亲节点给给右孩子的左边】
	void RotateL(Node* parent)
	{


		Node* SubR = parent->_right;
		Node* SubRL = SubR->_left;

		//旋转链接
		parent->_right = SubRL;
		SubR->_left = parent;

		Node* Parent_Parent = parent->_parent;

		parent->_parent = SubR;
		if (SubRL)
		{
			SubRL->_parent = parent;
		}

		//和父节点的父节点链接
		if (_root == parent)
		{
			_root = SubR;
			SubR->_parent = nullptr;
		}
		else
		{
			if (Parent_Parent->_left == parent)
			{
				Parent_Parent->_left = SubR;
			}
			else
			{
				Parent_Parent->_right = SubR;
			}
			SubR->_parent = Parent_Parent;
		}
		
	}

	//右单旋
	void RotateR(Node* parent)
	{

		Node* SubL = parent->_left;
		Node* SubLR = SubL->_right;

		//旋转链接
		//动一个节点就把他的父亲也变动
		parent->_left = SubLR;
		if (SubLR)//SubLR可能为空
		{
			SubLR->_parent = parent;
		}

		Node* Parent_Parent = parent->_parent;

		SubL->_right = parent;
		parent->_parent = SubL;

		//和父节点的父节点链接
		if (_root == parent)
		{
			_root = SubL;
			SubL->_parent = nullptr;
		}
		else
		{
			if (Parent_Parent->_left == parent)
			{
				Parent_Parent->_left = SubL;
			}
			else
			{
				Parent_Parent->_right = SubL;
			}
			SubL->_parent = Parent_Parent;//链接
		}
		
	}


	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

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

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

	//根节点到当前这条路径的黑色节点个数
	bool Check(Node *root,int blacknum,const int RefVal)
	{
		if (root == nullptr)
		{
			if (blacknum != RefVal)
			{
				return false;
			}
			return true;
		}
		//直接反向检查,儿子很复杂,父亲只有一个
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout<<"有连续的红节点" << endl;
			return false;
		}
		if (root->_col == BLACK)
		{
			blacknum++;
		}
		return Check(root->_left, blacknum, RefVal) && Check(root->_right, blacknum, RefVal);
	}

	bool IsBalance()
	{
		if (_root == nullptr)
		{
			return true;
		}
		if (_root->_col == RED)
		{
			return false;
		}


		int blacknum = 0;//记录每条路径的黑色节点个数
		int RefVal = 0;//定一个标准
		
		Node* cur = _root;
		while (cur)//改了一个bug ,之前这儿脑子抽抽了,写成了if
		{
			if (cur->_col == BLACK)
			{
				++RefVal;
			}
			cur = cur->_left;
		}
		return Check(_root, blacknum,RefVal);
	}

private:
	Node* _root = nullptr;
};

6. 红黑树的验证

红黑树的检测分为两步:

1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)

#include <vector>
#include "RBTree.h"

int main()
{
	int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	RBTree<int, int> a;
	for (auto e : arr)
	{
		a.insert(make_pair(e, e));
	}
	a.InOrder();
	return 0;
}

在这里插入图片描述


2. 检测其是否满足红黑树的性质

我们可以通过递归地遍历红黑树的节点,并统计根节点到每个叶子节点路径上的黑色节点个数来进行检查。

//根节点到当前这条路径的黑色节点个数
bool Check(Node *root,int blacknum,const int RefVal)
{
	if (root == nullptr)
	{
		if (blacknum != RefVal)
		{
			return false;
		}
		return true;
	}
	//直接反向检查,儿子很复杂,父亲只有一个
	if (root->_col == RED && root->_parent->_col == RED)
	{
		cout<<"有连续的红节点" << endl;
		return false;
	}
	if (root->_col == BLACK)
	{
		blacknum++;
	}
	return Check(root->_left, blacknum, RefVal) && Check(root->_right, blacknum, RefVal);
}

bool IsBalance()
{
	if (_root == nullptr)
	{
		return true;
	}
	if (_root->_col == RED)
	{
		return false;
	}


	int blacknum = 0;//记录每条路径的黑色节点个数
	int RefVal = 0;//定一个标准
	
	Node* cur = _root;
	while (cur)//改了一个bug ,之前这儿脑子抽抽了,写成了if
	{
		if (cur->_col == BLACK)
		{
			++RefVal;
		}
		cur = cur->_left;
	}
	return Check(_root, blacknum,RefVal);
}

函数讲解

Check 函数是一个递归函数,用于检查从当前节点到叶子节点的路径上的黑色节点个数是否与参考值 RefVal 相等。参数 root 表示当前节点指针,blacknum 表示根节点到当前节点的路径上的黑色节点个数,RefVal 是参考值。

  • 如果当前节点为空指针,即到达了叶子节点,那么检查路径上的黑色节点个数 blacknum 是否等于参考值 RefVal,如果不相等则返回 false,否则返回 true。
  • 如果当前节点的颜色为红色,并且父节点也是红色,表示存在连续的红节点,不符合红黑树的性质,返回 false。
  • 如果当前节点的颜色为黑色,将 blacknum 值加一。
  • 递归地调用 Check 函数检查左子节点和右子节点,并将当前节点的黑色节点个数 blacknum 作为参数传递。

IsBalance 函数用于检查整个红黑树是否符合红黑树的性质。

  • 如果红黑树为空树,即根节点为空,认为是一棵合法的红黑树,返回 true。
  • 如果根节点的颜色是红色,违反了红黑树的性质,返回 false。
  • 初始化 blacknum 为 0,用于记录每条路径的黑色节点个数。
  • 初始化 RefVal 为 0,作为参考值。
  • 通过遍历从根节点到最左子节点的路径,统计参考值 RefVal,即路径上的黑色节点个数。
  • 调用 Check 函数,传入根节点、路径上的黑色节点个数 blacknum 和参考值 RefVal 进行检查。
#include <vector>
#include "RBTree.h"
int main()
{
	const int N = 30;
	vector<int> v;
	v.reserve(N);
	srand(time(0));

	for (size_t i = 0; i < N; i++)
	{
		v.push_back(rand()%100 );
	}
	RBTree<int, int> t;
	for (auto e : v)
	{
		if (e == 0)
		{
			int i = 0;
		}
		t.insert(make_pair(e, e));
		cout << "Insert" << e << "->" << t.IsBalance() << endl;
	}
	t.InOrder();//中序打印
	if (t.IsBalance())
	{
		cout << "是平衡二叉树" << endl;
	}
	else
	{
		cout << "不是平衡二叉树" << endl;
	}
	return 0;
}

在这里插入图片描述

7. 红黑树与AVL树的比较

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

8. 红黑树的应用

  1. C++ STL库 – map/set、mutil_map/mutil_set
    C++ STL中的std::map和std::set:这些容器类通常使用红黑树作为底层数据结构,提供了高效的查找、插入和删除操作。

  2. 数据库系统:红黑树常被用作数据库索引结构,例如在关系型数据库中,可以使用红黑树来实现B+树索引,提供高效的数据检索和排序功能。

  3. 线程调度器:操作系统中的线程调度器通常需要高效地管理和调度线程,红黑树可用于实现定时器和任务调度器,以快速查找和处理就绪的线程。

  4. 路由算法:在网络路由算法中,红黑树可以用于快速查找最佳路径和路由表项,提供高效的路由查找和转发功能。

  5. linux内核
    文件系统:某些文件系统使用红黑树来管理文件和目录的索引,以支持快速的文件查找和访问。

  6. 编译器和解释器:在编译器和解释器中,红黑树可以用于符号表的实现,以支持快速的符号查找和关联。

  7. 并发数据结构:在多线程和并发编程中,红黑树可以用于实现并发安全的数据结构,例如并发哈希表、并发有序集合等。

(本章完)

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

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

相关文章

【日常总结】Swagger 3.0 + 集成 knife4j ,并设置header入参

一、场景 环境&#xff1a; 二、问题 思路 &#xff1a; 三、解决方案 &#xff08;推荐&#xff09; Stage 1&#xff1a;接入knife4j 依赖 Stage 2&#xff1a;修改 yaml 配置 Stage 3&#xff1a;修改 swagger 3 配置文件 Stage 4&#xff1a;查看效果 Swagger UI …

Junos webauth_operation.php 文件上传漏洞复现(CVE-2023-36844)

0x01 产品简介 Junos 是 Juniper Networks 生产的一款可靠的高性能网络操作系统。 0x02 漏洞概述 Junos webauth_operation.php接口处存在文件上传漏洞&#xff0c;未经身份认证的攻击者可利用 Junos 操作系统的 J-Web 服务 /webauth_operation.php 路由上传 php webshell&…

LVS-DR实验

实验前准备 DR服务器&#xff1a;192.168.188.11 192.168.188.15 NFS服务器&#xff1a;192.168.188.14 Web服务器1&#xff1a;192.168.188.12 Web服务器2&#xff1a;192.168.188.13 Vip&#xff1a;192.168.188.188 客户端&#xff1a;192.168.188.200 配置负载均衡调度…

05-学成在线课程分类查询

课程分类查询 界面原型 在新增课程基本信息界面中课程等级、课程类型、课程分类三处信息需要用户选择 当我们点击新增课程时,前端会请求内容管理服务中的content/course-category/tree-nodes接口获取课程分类表中的课程分类信息 响应数据模型 课程分类表course_category是一…

文件权限中 chmod、u+x、u、r、w、x分别代表什么

Linux系统中的每个文件和目录都有访问许可权限&#xff0c;如下面所示&#xff1a; 要说清楚问题&#xff0c;我们截取一些内容&#xff1a; ypyubuntu:~$ ls -l drwxr-xr-- 2 ypy ypy 4096 Nov 30 18:33 Desktop/ drwxr-xr-- 2 ypy ypy 4096 Nov 30 18:33 Documen…

Unity之NetCode多人网络游戏联机对战教程(10)--玩家动画同步

文章目录 前言NetworkAnimation服务端权威客户端权威 前言 这次的动画同步与位置同步&#xff0c;可以说实现思路是一样的&#xff0c;代码相似度也非常高 NetworkAnimation 如果直接挂载这个脚本只有Host&#xff08;服务端&#xff09;才可以同步&#xff0c;Client是没有…

迁移redis数据库中的数据到另一台服务器

方案一 下面我使用的redis是用docker安装的&#xff0c;不是通过下载安装包安装的&#xff0c;所以和我安装方式不一样的小伙伴可以不看&#xff0c;因为很多操作是基于docker的 话不多说&#xff0c;直接开搞&#xff01; 1.首先一定要确保两台服务器上面的redis版本要一致…

图解Redis适用场景

Redis以其速度而闻名。 1 业务数据缓存 1.1 通用数据缓存 string&#xff0c;int&#xff0c;list&#xff0c;map。Redis 最常见的用例是缓存对象以加速 Web 应用程序。 此用例中&#xff0c;Redis 将频繁请求的数据存储在内存。允许 Web 服务器快速返回频繁访问的数据。这…

vue day2

1、指令修饰符&#xff1a;.指明一些指令后缀&#xff0c;不同后缀封装不同处理操作 按键修饰符&#xff1a;keyup.enter v-model修饰符&#xff1a; v-model.trim&#xff1a;去首位空格 v-model.number&#xff1a;转数字 事件修饰符&#xff1a; 阻止事件冒泡&#xff1…

机器人制作开源方案 | 网球自动拾取机

作者&#xff1a;柳文浩、李浩杰、苏伟男、贾思萌、张天芸 单位&#xff1a;西安外事学院 指导老师&#xff1a;胡宝权、陈小虎 1. 产品说明 1.1 设计目的 近年来&#xff0c;网球运动越来越受到老百姓的欢迎&#xff0c;各种规模的比赛层出不穷。然而由于网球运动极为激烈…

滴滴昨晚崩了,看这波还敢不敢降本增效?

起因 截至 2023 年 11 月 27 日晚&#xff0c;中国最大的网约车服务平台滴滴打车遭遇系统崩溃&#xff0c;继阿里云控制台故障之后&#xff0c;再次引发热议。这一事件迅速攀升至热搜榜首&#xff0c;引起广泛关注。 今晚约 10 点&#xff0c;滴滴打车遭遇大范围技术故障。用户…

Spring的三种常见Bean的初始化参数机制,你都用对了吗?

大家好&#xff0c;我是G探险者。 spring这本九阳神功秘籍&#xff0c;我们一点一滴去研读。 在Spring框架中&#xff0c;Bean的实例化与初始化是一个复杂的过程&#xff0c;一个Bean的实例化过程往往伴随着一些属性的初始化动作&#xff0c;有的是在Bean实例化之后才进行的属…

解决VMware VCenter存储上传镜像文件失败

VMware VCSA6.7上传共享文件时提示操作失败&#xff0c;由于不确定的原因&#xff0c;操作失败。通常&#xff0c;当浏览器不信任证书时会发生此问题。如果您使用的是自签名证书或自定义证书&#xff0c;请在新的浏览器选项卡中打开下面的 URL并接受证书&#xff0c;然后重试操…

五、Lua流程控制与函数

一、流程控制 &#xff08;一&#xff09;含义 Lua 编程语言流程控制语句通过程序设定一个或多个条件语句来设定。在条件为 true 时执行指定程序代码&#xff0c;在条件为 false 时执行其他指定代码。 &#xff08;二&#xff09;原型 if (成立) then执行体1else执行体2 end…

蓝桥杯每日一题2023.11.27

题目描述 星系炸弹 - 蓝桥云课 (lanqiao.cn) 题目分析 对于此题目一一枚举即可 #include<bits/stdc.h> using namespace std; bool is_r(int n) {if((n % 4 0 && n % 100 ! 0)|| n % 400 0)return true;return false; } int mm[13] {0, 31, 28, 31, 30, 3…

智能优化算法应用:基于樽海鞘群算法无线传感器网络(WSN)覆盖优化 - 附代码

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

图像分类任务

本文记录 北京邮电大学 计算机学院的学习记录 什么是图像分类任务&#xff1f; 图像分类任务是计算机视觉中的核心任务&#xff0c;其目 标是根据图像信息中所反映的不同特征&#xff0c;把不同类别 的图像区分开来 图像分类任务有哪些难点呢&#xff1f; 语义鸿沟视角变化…

【springboot】宝塔简单部署springboot 配置https

宝塔简单部署springboot配置https 需求步骤1. springboot通过maven组件打成jar包2. 将jar包部署到宝塔上3. 下载安装nginx并创建网站节点4. 设置域名或者IP5. 设置反向代理:代理后端服务的ip和端口7. 配置SSL/TLS 需求 宝塔部署springboot项目,用nginx反向代理后端IP端口&…

用Elasticsearch搜索匹配功能实现基于地理位置的查询

1.Redis,MongoDB,Elasticsearch实现地理位置查询比较 1.1 Redis: 优点&#xff1a;Redis提供了地理空间索引功能&#xff0c;可以通过Geo数据类型进行地理位置查询。这使得Redis在处理地理位置查询时非常高效。 缺点&#xff1a; Redis的地理空间索引功能相对简单&#xff0…

【单调栈】最大宽度坡

public int maxWidthRamp(int[] nums) {/* 此方法思路正确&#xff0c;但超时int n nums.length;Deque<Integer> stack;int max 0;for (int i 0; i < n; i) {stack new LinkedList<>();stack.push(nums[i]);int j i 1;while (j < n) {stack.push(nums…