当前位置: 首页 > news >正文

【C++进阶】红黑树

目录

  • 什么是红黑树?
    • 红黑树
    • 红黑树的性质
  • 定义红黑树
  • 红黑树的操作
    • insert
    • inorder
    • find
    • height
    • size
    • 构造函数
    • 析构函数
    • 赋值拷贝
    • 判断红黑树
  • 全部代码
  • 总结

在这里插入图片描述

什么是红黑树?

红黑树

红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,用于保持树的平衡,以确保在最坏情况下基本操作(如插入、删除和查找)的时间复杂度仍为 O(log n)。红黑树的每个节点都包含一个额外的颜色位,即红色或黑色。红黑树通过严格的平衡条件来维持树的平衡。

红黑树的性质

  1. 节点是红色或黑色的:每个节点都有颜色属性,红色或黑色。
  2. 根是黑色的:红黑树的根节点必须是黑色的。
  3. 叶节点(NIL 节点)是黑色的:红黑树中的所有叶节点(这里的叶节点是指为空的 NIL 节点,而不是实际的元素节点)都是黑色的。
  4. 红色节点的子节点必须是黑色的(即红色节点不能有红色子节点,也叫“红黑相间”):红色节点不能连续连接在一起。
  5. 从任何节点到其每个叶子的所有简单路径都必须包含相同数量的黑色节点:这确保了树的平衡性。

定义红黑树

enum Color
{RED,BLACK,
};
template<class K, class V>
struct RBTreeNode
{pair<K, V> _kv;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Color _col;RBTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr){}
};
template<class K,class V> 
class RBTree
{
public:typedef RBTreeNode<K, V> Node;
private:Node* _root = nullptr;
};

红黑树的操作

insert

红黑树的逻辑是在普通的二叉搜索树上进行实现的,在普通的二叉搜索树中,我们不需要调节平衡,但是在红黑树当中我们需要根据红黑树的性质来调整数的颜色和高度,首先我们来看看第一种情况:
在这里插入图片描述
cur是插入节点,由于红色节点不能连续,所以这里已经破坏了平衡,所以我们应该进行调整颜色,我们不可能插入cur是黑色节点,因为如果插入黑色节点的话代价很大,每条路上都会多出来一个黑色节点,这样很不好维护,所以插入红色节点是代价最小的,插入红色节点之后,破坏了规则,所以p应该变成黑色,由于p这条路多了一个黑色节点,所以u应该也变成黑色节点,由于这棵树有可能是某个子树,这两条路多出来一个黑色节点为了保证黑色节点不多,所以g节点应该也变成红色,这样做完之后继续往上调整,将cur赋值到g节点,继续往上调整颜色。

在这里插入图片描述
这样就算调整完毕了。
第二种情况:当u节点不存在时
在这里插入图片描述
对于这种情况我们先准备调色,首先我们先将p改为黑色节点,然后将g改为红色节点之后,我们会发现,左边这条路多出来一个黑色节点,这样是不行的。
在这里插入图片描述
上面这个是不行的,左边已经多出来了一个黑色节点了,但是右边没有黑色节点,所以这种情况我们应该进行旋转。
对g节点进行右旋:
在这里插入图片描述
进行右旋之后将p改为黑色节点,将g改为红色节点,这样两边都保持平衡了。
在这里插入图片描述
还有一种情况:u存在但是为黑色
在这里插入图片描述

最下面的那个红色节点是插入节点:
这种情况我们先向上调整:
在这里插入图片描述
调整成这样之后,我们就发现,u是黑色节点,不管我们怎么调整,左边都会多出一个黑色节点,所以这里我们应该旋转:
绕着g节点进行旋转之后我们可以发现调整颜色就会平衡:
在这里插入图片描述
还有双旋的情况,双旋的情况,我们只说一种:
在这里插入图片描述
左旋将p和cur的位置交换,然后再对g进行右旋,就可以达到平衡的效果。

左旋接口:

void RotateL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parentParent == nullptr){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left)parentParent->_left = subR;else parentParent->_right = subR;subR->_parent = parentParent;}
}

右旋接口:

void RotateR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;if (parentParent == nullptr){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subL;else parentParent->_right = subL;subL->_parent = parentParent;}
}

insert的代码:

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);cur->_col = RED;//插入到右边if (parent->_kv.first < kv.first)parent->_right = cur;else parent->_left = cur;cur->_parent = parent;//调整颜色或旋转//parent不为空并且parent指向的颜色是红色才进行调整while (parent && parent->_col == RED){Node* grandparent = parent->_parent;if (grandparent->_left == parent){Node* uncle = grandparent->_right;//uncle存在且是红色if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}//uncle不存在或者存在为黑色else{//判断cur是parent的左子树还是右子树://右单旋if (cur == parent->_left){RotateR(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateL(parent);RotateR(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}else{Node* uncle = grandparent->_left;//uncle存在且是红色if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}//uncle不存在或者存在为黑色else{//判断cur是parent的左子树还是右子树://右单旋if (cur == parent->_right){RotateL(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateR(parent);RotateL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}}_root->_col = BLACK;return true;
}

inorder

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

find

bool Find(const K& k)
{Node* cur = _root;while (cur){if (cur->_kv.first < k) cur = cur->_right;else if (cur->_kv.first > k) cur = cur->_left;else return true;}return false;
}

height

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 max(leftheight, rightheight) + 1;
}

size

int size()
{return _size(_root);
}
int _size(Node* root)
{if (root == nullptr)return 0;int left = _size(root->_left);int right = _size(root->_right);return left + right + 1;
}

构造函数

//默认构造
RBTree() = default;
//拷贝构造
RBTree(const RBTree<K, V>& t)
{_root = Copy(t._root);
}
Node* Copy(Node* root)
{if (root == nullptr)return nullptr;Node* newnode = new Node(root->_kv);newnode->_left = Copy(root->_left);newnode->_right = Copy(root->_right);return newnode;
}

析构函数

~RBTree()
{Destroy(_root);_root = nullptr;
}
void Destroy(Node* root)
{if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;
}

赋值拷贝

RBTree<K, V>& operator=(RBTree<K, V> t)
{swap(_root, t._root);return *this;
}

判断红黑树

bool IsBalance()
{//空树也是搜索树if (_root == nullptr) return true;//根节点不能为红色if (_root->_col == RED) return false;//参考值int refNum = 0;Node* cur = _root;while (cur){//遇到黑色++if (cur->_col == BLACK) refNum++;cur = cur->_left;}return Check(_root, 0, refNum);
}
bool Check(Node* root, int blackNum, const int refNum)
{//走到空之后就算出一条路径的数量了if (root == nullptr){if (blackNum != refNum){cout << "存在黑色节点不相等的路径" << endl;return false;}return true;}//存在连续的红色节点if (root->_col == RED && root->_parent->_col == RED)return false;if (root->_col == BLACK)blackNum++;return Check(root->_left, blackNum, refNum) && Check(root->_right, blackNum, refNum);
}

全部代码

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
enum Color
{RED,BLACK,
};
template<class K, class V>
struct RBTreeNode
{pair<K, V> _kv;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Color _col;RBTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr){}
};
template<class K,class V> 
class RBTree
{
public:typedef RBTreeNode<K, V> Node;//默认构造RBTree() = default;//拷贝构造RBTree(const RBTree<K, V>& t){_root = Copy(t._root);}//赋值拷贝RBTree<K, V>& operator=(RBTree<K, V> t){swap(_root, t._root);return *this;}//析构函数~RBTree(){Destroy(_root);_root = nullptr;}//查找bool Find(const K& k){Node* cur = _root;while (cur){if (cur->_kv.first < k) cur = cur->_right;else if (cur->_kv.first > k) cur = cur->_left;else return true;}return false;}//中序遍历void InOrder(){_InOrder(_root);}//插入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);cur->_col = RED;//插入到右边if (parent->_kv.first < kv.first)parent->_right = cur;else parent->_left = cur;cur->_parent = parent;//调整颜色或旋转//parent不为空并且parent指向的颜色是红色才进行调整while (parent && parent->_col == RED){Node* grandparent = parent->_parent;if (grandparent->_left == parent){Node* uncle = grandparent->_right;//uncle存在且是红色if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}//uncle不存在或者存在为黑色else{//判断cur是parent的左子树还是右子树://右单旋if (cur == parent->_left){RotateR(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateL(parent);RotateR(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}else{Node* uncle = grandparent->_left;//uncle存在且是红色if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent;parent = cur->_parent;}//uncle不存在或者存在为黑色else{//判断cur是parent的左子树还是右子树://右单旋if (cur == parent->_right){RotateL(grandparent);grandparent->_col = RED;parent->_col = BLACK;}else{RotateR(parent);RotateL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}}_root->_col = BLACK;return true;}//大小int size(){return _size(_root);}//树的高度int height(){return _height(_root);}
private:int _height(Node* root){if (root == nullptr)return 0;int leftheight = _height(root->_left);int rightheight = _height(root->_right);return max(leftheight, rightheight) + 1;}int _size(Node* root){if (root == nullptr)return 0;int left = _size(root->_left);int right = _size(root->_right);return left + right + 1;}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parentParent == nullptr){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left)parentParent->_left = subR;else parentParent->_right = subR;subR->_parent = parentParent;}}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;if (parentParent == nullptr){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subL;else parentParent->_right = subL;subL->_parent = parentParent;}}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ':' << root->_kv.second << endl;_InOrder(root->_right);}void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* newnode = new Node(root->_kv);newnode->_left = Copy(root->_left);newnode->_right = Copy(root->_right);return newnode;}Node* _root = nullptr;
};

总结

红黑树作为一种自平衡二叉搜索树,通过严格的颜色和旋转规则,保证了在最坏情况下仍能提供高效的查找、插入和删除操作。其特有的平衡机制使得红黑树在实际应用中被广泛采用,尤其在需要频繁增删节点的数据结构中表现出色。掌握红黑树的原理和操作,不仅有助于理解复杂数据结构的实现,也为开发高效算法奠定了坚实基础。希望通过本篇博客,大家能够对红黑树有更加深入的认识,并在实际编程中灵活应用。

相关文章:

【C++进阶】红黑树

目录 什么是红黑树&#xff1f;红黑树红黑树的性质 定义红黑树红黑树的操作insertinorderfindheightsize构造函数析构函数赋值拷贝判断红黑树 全部代码总结 什么是红黑树&#xff1f; 红黑树 红黑树&#xff08;Red-Black Tree&#xff09;是一种自平衡的二叉搜索树&#xff…...

linux使用ssh连接一直弹出密码框问题

1.查看ssh服务的状态 输入以下命令&#xff1a; sudo service sshd status 小编已经安装了。 如果出现 Loaded: error (Reason: No such file or directory) 提示的话&#xff0c;说名没有安装ssh服务&#xff0c;按照第二步&#xff1a;安装ssh服务。 如果出现 Active: in…...

Python 3 数据结构

Python 3 数据结构 引言 Python 是一种高级编程语言&#xff0c;因其简洁明了的语法和强大的功能而广受欢迎。在 Python 中&#xff0c;数据结构是组织和存储数据的方式&#xff0c;对于编写高效和可维护的代码至关重要。本文将深入探讨 Python 3 中的主要数据结构&#xff0…...

【开源社区】Elasticsearch(ES)中空值字段 null_value 及通过exists查找非空文档

文章目录 0、声明1、问题描述2、问题剖析2.1 NULL或者空值类型有哪些2.2 案例讲解&#xff1a;尝试检索值为 null 的字段2.3 解决思路 3、使用 null_value 的诸多坑&#xff08;避免生产事故&#xff09;3.1 null_value 替换的是索引&#xff0c;并不会直接替换源数据3.2 不支持…...

JavaDS —— 位图(BitSet)与 布隆过滤器

位图 引入问题&#xff1a;给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中。 首先要注意 40 亿个数据如果使用 整型&#xff08;int) 来存放的话&#xff0c;就是要 40 亿个整型&#xff0c;一个整型有…...

如何确保场外个股期权交易的安全?

如何确保场外个股期权交易的安全&#xff1f;投资者可以采取以下措施&#xff0c;以提高交易的安全性和减少风险&#xff1a; 增强知识储备&#xff1a;深入学习期权的基础知识&#xff0c;包括不同类型的期权、它们的权利和义务、定价方式以及风险特性&#xff0c;从而提升自…...

第2章:LabVIEW FPGA未来发展方向《LabVIEW ZYNQ FPGA宝典》

2.1&#xff1a;NI的LabVIEW FPGA未来战略部署 在展望NI公司的LabVIEW FPGA技术未来发展趋势之前&#xff0c;让我们先来回顾一下LabVIEW与FPGA的技术发展历程&#xff0c;如图2-1所示。可以看出&#xff0c;NI公司的LabVIEW FPGA软件一方面是跟随Xilinx最新的FPGA硬件可持续发…...

苹果电脑维护工具:CleanMyMac X让你的Mac焕发新生!

在我们的数字生活中&#xff0c;苹果电脑&#xff08;Mac&#xff09;已成为不可或缺的一部分&#xff0c;无论是为工作披星戴月&#xff0c;还是为娱乐畅游云端。但是&#xff0c;就像任何长时间运行的机器一样&#xff0c;Mac也可能会因为积累的文件和不必要的数据而开始变慢…...

MySQL2 DML数据操纵语言和SQL约束

DML和SQL约束 SQL-DML1.添加数据2.修改数据3.删除 TRUNCATE和DELETE的区别&#xff1a;SQL-约束Primary Key创建主键约束单列主键联合主键**验证主键约束**删除主键约束设置主键自增AUTO_INCREMENTdelete和truncate删除后&#xff0c;主键的自增 SQL-唯一约束UNIQUE创建唯一约束…...

Ubuntu 20.04 中安装 Nginx (通过传包编译的方式)、开启关闭防火墙、开放端口号

文章目录 前言一、安装包下载二、上传服务器并解压缩三、依赖配置安装四、生成编译脚本五、编译六、查看是否编译完成七、开始安装八、查看是否安装成功九、设置为开机自启动 前言 参考大佬文章并在基础上做了点修改&#xff0c;发篇文章记录下 防止下次遇到。 参考文章&#…...

解决no main manifest attribute错误

文章目录 0. 背景1. java程序如何运行2. jar是什么3. java -jar test-1.0-SNAPSHOT.jar&#xff1a;4. 添加执行入口 0. 背景 在开发Spring boot项目的时候&#xff0c;有时候会需要使用java -jar test-1.0-SNAPSHOT.jar指令来运行开发的java应用&#xff0c;但是很不幸&#…...

002 | 常见的金融量化指标计算

金融量化指标 在金融量化分析中&#xff0c;常用的指标可以帮助我们判断市场走势、评估风险和收益&#xff0c;以及构建交易策略。以下是一些常见的金融量化指标及其计算方法的详细教程&#xff0c;包括公式与Python代码实现。 1. 移动平均线&#xff08;Moving Average, MA&…...

Web Vitals:提升用户体验的关键指标

Web Vitals 是 Google 提出的一套核心网页性能指标&#xff0c;旨在帮助开发者理解和优化网站的用户体验。这些指标分为核心 Web Vitals 和附加 Web Vitals&#xff0c;涵盖了加载性能、交互性和视觉稳定性三个方面。以下是详细的介绍和如何使用 Web Vitals 来优化你的网站。 …...

c#中的约束、TimeSpan、defult、operator

c#中的约束 在C#中&#xff0c;约束&#xff08;Constraints&#xff09;用于限制泛型类型参数的类型&#xff0c;以确保泛型类型或方法在编译时能够满足特定的要求。约束允许开发者指定泛型类型参数必须满足的条件&#xff0c;比如实现特定的接口或继承自特定的类。以下是一些…...

挖矿木马攻破了服务器

最近被国外的挖矿木马攻破了服务器 根据非法登录&#xff0c;用 #last指令查看登录ip 首先删掉登录主机 #kill -9 pts/0 第二步 #top 看看什么占用cpu高 第三步杀死狂刷CPU的服务 过一分钟后&#xff0c;服务又开始狂刷cpu。 第四步根据pid查到服务地址 #systemctl status…...

从容应对技术面试:策略、技巧与成功案例

欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 工💗重💗hao💗:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来:详细讲解AIGC的概念、核心技术、应用领域等内容。 ⭐…...

Spring Boot 整合 RestTemplate:详解与实战

Spring Boot 整合 RestTemplate&#xff1a;详解与实战指南 一、引言二、依赖添加Maven 示例&#xff1a;Gradle 示例&#xff1a; 三、创建 RestTemplate 实例四、使用 RestTemplate 发起请求五、处理响应六、高级用法1. 自定义 RestTemplate 实例2. 文件上传、下载以及常见的…...

【利用模板模式和责任链模式实现数据校验】

利用模板模式和责任链模式实现数据校验 一、业务背景二、模板模式和责任链模式代码实现1、数据校验抽象处理器ValidateHandler2、数据校验责任链工具类ValidateChainUtil3、网元调整数据校验抽象类AbstractNodeCheckHandler4、依次定义3个责任链handler&#xff0c;通过Order注…...

学习笔记第十九天

1.标准I/O的基本概念 标准输入&#xff08;stdin&#xff09;&#xff1a;默认是指键盘输入。 标准输出&#xff08;stdout&#xff09;&#xff1a;默认是指显示器输出。 标准错误&#xff08;stderr&#xff09;&#xff1a;用于输出错误信息&#xff0c;也是指向显示器&…...

设计模式 - 单例模式

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、单例模…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...

Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解

文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一&#xff1a;HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二&#xff1a;Floyd 快慢指针法&#xff08;…...

Java中栈的多种实现类详解

Java中栈的多种实现类详解&#xff1a;Stack、LinkedList与ArrayDeque全方位对比 前言一、Stack类——Java最早的栈实现1.1 Stack类简介1.2 常用方法1.3 优缺点分析 二、LinkedList类——灵活的双端链表2.1 LinkedList类简介2.2 常用方法2.3 优缺点分析 三、ArrayDeque类——高…...

基于Python的气象数据分析及可视化研究

目录 一.&#x1f981;前言二.&#x1f981;开源代码与组件使用情况说明三.&#x1f981;核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.&#x1f981;演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...