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

【C++】—— set 与 multiset

【C++】—— map 与 set

  • 1 序列式容器和关联式容器
  • 2 set 系列的使用
    • 2.1 set 和 multiset 参考文档
    • 2.2 set 类的介绍
    • 2.3 set 的迭代器和构造
    • 2.4 set的增删查
      • 2.4.1 insert
      • 2.4.2 find 与 erase
      • 2.4.3 count
    • 2.5 lower_bound 与 upper_bound
    • 2.6 multiset 与 set 的差异
      • 2.6.1 不再去重
      • 2.6.2 find 返回中序的第一个
      • 2.6.3 erase 删除所有的 x
      • 2.6.4 count 个数

1 序列式容器和关联式容器

  前面我们已经接触过 STL 中的部分容器如:stringvectorlistdequearray等,这些容器统称为序列式容器,因为他们是逻辑结构为线性序列的数据结构(物理结构不一定为线性),两个位置存储的值之间一般没有紧密的关联关系,比如交换一下,它依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的

  关联式容器也是用来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是非线性结构,两个位置有紧密的关联关系,交换一下,他的存储结构就被破坏了。关联式容器中的元素是按关键字来保存和访问的。关联式容器有 map / set 系列和 unordered_map / unordered_set 系列

  本文讲解的 m a p map map s e t set set 底层是红黑树,红黑树是一颗平衡二叉搜索树。 s e t set set k e y key key 搜索场景的结构, m a p map map k e y key key / v a l u e value value 搜索场景的结构
  
  

2 set 系列的使用

2.1 set 和 multiset 参考文档

 https://legacy.cplusplus.com/reference/set/

  

2.2 set 类的介绍

set 的声明如下:

template < class T,                        // set::key_type/value_typeclass Compare = less<T>,        // set::key_compare/value_compareclass Alloc = allocator<T>      // set::allocator_type> class set;

s e t set set 的声明如上,T 就是 s e t set set 底层关键字的类型
  
s e t set set 默认要求 T 支持小于比较,如果不支持或者想按自己的需求走可以自行实现仿函数传给第⼆个模版参数
  
s e t set set 底层存储数据的内存是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个参数。
  
• ⼀般情况下,我们都不需要传后两个模版参数。
  
s e t set set 底层是用红黑树实现,增删查效率是 O(logN),迭代器遍历是⾛的搜索树的中序,所以是有序的。
  
• 前面部分我们已经学习了 v e c t o r vector vector / l i s t list list 等容器的使用,STL 容器接口设计,高度相似,所以这里我们就不再⼀个接口⼀个接口的介绍,而是直接带着大家看文档,挑比较重要的接口进行介绍。

  这里库中的模板参数用的是 T,个人认为这里设计的不够好,既然是搜索,那用 Key 更好,我们可以将其当成是 Key,虽然库中没用这个名字。
  

2.3 set 的迭代器和构造

   s e t set set 的迭代器是一个双向迭代器

在这里插入图片描述

// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

  

s e t set set 主要构造方式如下:

  • 无参构造
explicit set(const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
  • 迭代器区间构造
template <class InputIterator>
set(InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
  • 拷贝构造
set(const set& x);
set(const set& x, const allocator_type& alloc);
  • 列表构造
set(initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());

  

2.4 set的增删查

  首先要注意的是: s e t set set 是不支持改的,因为 s e t set set 属于关联式容器,对齐进行数据修改会破坏它的存储结构
  

2.4.1 insert

// 单个数据插⼊,如果已经存在则插⼊失败
pair<iterator, bool> insert(const value_type& val);// 列表插⼊,已经在容器中存在的值不会插⼊
void insert(initializer_list<value_type> il);// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert(InputIterator first, InputIterator last);

  这里 v a l u e value value_ t y p e type type 就是 T,即 Key;此外 k e y key key_ t y p e type type 也是 T。这里这么设计是为了和后面的 m a p map map 保持一致

在这里插入图片描述

  返回值 pair<iterator, bool> 这里还不需要用到它,暂不解释,在后面的 m a p map map 部分会详细介绍。
  
举个栗子:

int main()
{// 去重+升序排序set<int> s;// 去重+降序排序(给⼀个⼤于的仿函数)//set<int, greater<int>> s;s.insert(5);s.insert(2);s.insert(7);s.insert(5);set<int>::iterator it = s.begin();while (it != s.end()){// error C3892: “it”: 不能给常量赋值// *it = 1;cout << *it << " ";++it;}cout << endl;return 0;
}

运行结果:

在这里插入图片描述

  可以看到, s e t set set 是不允许两个相同的值进行插入的, s e t set set 有去重功能。并且 s e t set set 是不允许修改的*it = 1 进行修改会报错。
  默认 s e t set set 走的是升序,如果想走降序,可以传递一个大于的仿函数。迭代器的底层走的是一个中序遍历

   s e t set set 支持列表插入

int main()
{set<int> s;s.insert({ 2,8,3,9,2 });for (auto e : s){cout << e << " ";} cout << endl;return 0;
}

  
   s e t set set 除了支持整型,其他任意类型都是可以的(如果该类型不支持比较,需自己传递仿函数),我们以 s t r i n g string string 为例

int main()
{// void insert(initializer_list<value_type> il);// 构造出临时对象再拷贝构造,优化成直接构造set<string> strset = { "sort", "insert", "add" };// 遍历string⽐较ascll码⼤⼩顺序遍历的for (auto& e : strset){cout << e << " ";} return 0;
}

  

2.4.2 find 与 erase

const_iterator find(const value_type& val) const;
iterator       find(const value_type& val);

   f i n d find find 返回的是对应位置的迭代器,如果没找到就返回 end()

  • 迭代器删除
iterator  erase(const_iterator position);
  • Key删除
size_type erase(const value_type& val);

   s i z e size size_ t y p e type type 是一个无符号整型,即 u n s i g n e d unsigned unsigned i n t int int,返回的是删除元素的个数
  如果删除成功,表示删除了一个值,返回 1;删除失败,表示没有删除值,返回 0

  为什么这里不用 b o o l bool bool 呢?这里是为了兼容 m u l t i s e t multiset multiset
   m u l t i s e t multiset multiset 中允许相同数插入的,可能 e r a s e erase erase 多个相同的值,这时就不能用 b o o l bool bool

  • 迭代器区间删除
iterator  erase(const_iterator first, const_iterator last);

  

栗子

int main()
{set<int> s = { 4,2,7,2,8,5,9 };for (auto e : s){cout << e << " ";} cout << endl;// 删除最⼩值s.erase(s.begin());for (auto e : s){cout << e << " ";}cout << endl;// 直接删除xint x;cin >> x;int num = s.erase(x);if (num == 0){cout << x << "不存在!" << endl;} for (auto e : s){cout << e << " ";}cout << endl;// 直接查找在利⽤迭代器删除xcin >> x;auto pos = s.find(x);if (pos != s.end()){s.erase(pos);}else{cout << x << "不存在!" << endl;}for (auto e : s){cout << e << " ";} cout << endl;return 0;
}

  
   s e t set set 进行删除同样会导致 迭代器失效

i )
在这里插入图片描述
  
  此时删除的是叶子结点 1,删除后迭代器中的指针为野指针迭代器失效

  

ii )

在这里插入图片描述
   删除 6 节点。它要与 5 或 7 节点进行交换,删除进行删除。虽然此时迭代器中的指针并不是野指针,但它原来的意义已经改变了,我们也认为是迭代器失效
  
  而且从我们的角度,我们不知道这个节点是直接删除还是替代法删除

p s ps ps:对二叉搜索树的删除有不理解的小伙伴可移步至:【C++】—— 二叉搜索树

  

2.4.3 count

   c o u n t count count 的功能是返回 v a l u e value value_ t y p e type type 在容器中的个数

size_type count (const value_type& val) const;

   c o u n t count count 是给 m u l t i s t multist multist 设计的,因为对 s e t set set 而言 c o u n t count count 要么返回 1 要么返回 0,并没有什么意义。但对于 m u l t i s e t multiset multiset 就不一样, m u l t i s e t multiset multiset 是允许多个相同值存在的

  我们可以 c o u n t count count 来判断一个 K e y Key Key 在不在,在的话返回的是 1,不在返回 0。
  而且用 c o u n t count count 来判断往往比 f i n d find find 更方便,因为 f i n d find find 返回的是迭代器,迭代器 != end() 才是找到了

int main()
{set<int> s = { 4,2,7,2,8,5,9 };// 利⽤count间接实现快速查找int x;cin >> x;if (s.count(x)){cout << x << "在!" << endl;} else{cout << x << "不存在!" << endl;} return 0;
}

  

2.5 lower_bound 与 upper_bound

// 返回⼤于等于val位置的迭代器
iterator lower_bound(const value_type& val) const;
// 返回⼤于val位置的迭代器
iterator upper_bound(const value_type& val) const;

   l o w e r lower lower_ b o u n d bound bound u p p e r upper upper_ b o u n d bound bound 是为了方便查找一段区间
  我们曾经说过,在 STL 里面,只要是迭代器区间必须是 左闭右开,这时就可以用到 l o w e r lower lower_ b o u n d bound bound u p p e r upper upper_ b o u n d bound bound

举个栗子:


int main()
{std::set<int> myset;for (int i = 1; i < 10; i++)myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90for (auto e : myset){cout << e << " ";}cout << endl; 实现查找到的[itlow,itup)包含[30, 60]区间 返回 >= 30(这里即返回30)//auto itlow = myset.lower_bound(30); 返回 > 60(这里即返回70)//auto itup = myset.upper_bound(60);// 实现查找到的[itlow,itup)包含[25, 55]区间//对应别人来说,并不知道容器里面是否有 25 和 55,但是查找这段区间的方法与查找30-60的方法一样的// 返回 >= 25(这里即返回30)auto itlow = myset.lower_bound(25);// 返回 > 55(这里即返回60)auto itup = myset.upper_bound(55);// 删除这段区间的值myset.erase(itlow, itup);for (auto e : myset){cout << e << " ";}cout << endl;return 0;
}

  

2.6 multiset 与 set 的差异

   m u l t i s e t multiset multiset s e t set set 的使用基本完全类似,主要区别点在于 m u l t i s e t multiset multiset 支持值冗余,那么 i n s e r t insert insert / f i n d find find / c o u n t count count / e r a s e erase erase 都围绕着支持值冗余有所差异,具体参看下面的样例代码理解。

2.6.1 不再去重

  • 相比 s e t set set 不同的是, m u l t i s e t multiset multiset 是排序,但是不去重
int main()
{multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };auto it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;return 0;
}

  

2.6.2 find 返回中序的第一个

  • 相比 s e t set set 不同的是, x x x 可能会存在多个, f i n d find find 查找中序遍历的第一个
int main()
{multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };int x;cin >> x;auto pos = s.find(x);while (pos != s.end() && *pos == x){cout << *pos << " ";++pos;} cout << endl;return 0;
}

  简单讲一下他是怎么找到中序的第一个的。
  查找依然是 O(logN) 算法的查找,并不是通过中序的方式遍历一遍,这样的话二叉搜索树就失去其意义。
  中序的查找规则是:左子树 -> 根 -> 右子树
  假设要找的值是 5 :如果找到了一个 5 ,就再往其左子树找,因为中序第一个 5 一定是在左树;直到找到了某一个 5 ,并且其左子树没有 5 ,表面当前 5 就是中序的第一个 5。
  
  为什么这里要找中序的第一个呢? 因为找中序的第一个 x,就可以用迭代器不断++,就可以找到所有的 x
  

2.6.3 erase 删除所有的 x

  • 相比 s e t set set 不同的是, e r a s e erase erase 给值时会删除所有的 x
int main()
{multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };for (auto e : s){cout << e << " ";} cout << endl;int x;cin >> x;s.erase(x);for (auto e : s){cout << e << " ";} cout << endl;return 0;
}

  

2.6.4 count 个数

  • 相比 s e t set set 不同的是, c o u n t count count 会返回 x x x实际个数
int main()
{multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };for (auto e : s){cout << e << " ";}cout << endl;int x;cin >> x;cout << s.count(x) << endl;return 0;
}

  
  
  
  
  


  好啦,本期关于 s e t set set m u l t i s e t multiset multiset 的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在 C++ 的学习路上一起进步!

相关文章:

【C++】—— set 与 multiset

【C】—— map 与 set 1 序列式容器和关联式容器2 set 系列的使用2.1 set 和 multiset 参考文档2.2 set 类的介绍2.3 set 的迭代器和构造2.4 set的增删查2.4.1 insert2.4.2 find 与 erase2.4.3 count 2.5 lower_bound 与 upper_bound2.6 multiset 与 set 的差异2.6.1 不再去重2…...

蓝桥杯-扫雷

这题不难&#xff0c;就是麻烦一点&#xff0c;这里暴力求解了直接 题目链接&#xff1a; 扫雷 AC代码&#xff1a; import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan ne…...

黑马JavaWeb-day06、07、08(SQL部分) _

文章目录 MYSQL概述数据模型SQL简介SQL分类 DDL数据库操作表操作 DML增&#xff08;INSERT&#xff09;改&#xff08;UPDATE&#xff09;删&#xff08;DELETE&#xff09; DQL基本查询条件查询&#xff08;where&#xff09;分组查询&#xff08;group by&#xff09;排序查询…...

三十五:Wireshark的捕获过滤器

Wireshark 是一个广泛使用的网络协议分析工具&#xff0c;主要用于捕获和分析网络流量。它支持丰富的协议分析&#xff0c;并提供了多种过滤方式&#xff0c;以便用户在大量数据中精确地找到自己关注的内容。在Wireshark中&#xff0c;过滤器可以分为两类&#xff1a;捕获过滤器…...

第9章 大模型的有害性(上)

9.1 引言 本章将探讨大型语言模型&#xff08;LLMs&#xff09;可能带来的有害性&#xff0c;重点讨论以下几个方面&#xff1a; 性能差异社会偏见和刻板印象 在后续内容中&#xff0c;还会涉及其他层面的危害&#xff0c;如有害信息、虚假信息、隐私和安全风险、版权问题、…...

遗传算法与深度学习实战(26)——编码卷积神经网络架构

遗传算法与深度学习实战&#xff08;26&#xff09;——编码卷积神经网络架构 0. 前言1. EvoCNN 原理1.1 工作原理1.2 基因编码 2. 编码卷积神经网络架构小结系列链接 0. 前言 我们已经学习了如何构建卷积神经网络 (Convolutional Neural Network, CNN)&#xff0c;在本节中&a…...

Linux无线网络配置工具:iwconfig vs iw

在Linux系统中&#xff0c;无线网络配置和管理是网络管理员和开发者的常见任务。本文将详细介绍两个常用的无线网络配置命令行工具&#xff1a;iwconfig 和 iw&#xff0c;并对比它们之间的区别&#xff0c;帮助您更好地选择合适的工具进行无线网络配置。 一、iwconfig 简介 …...

RabbitMQ介绍及安装

文章目录 一. MQ二. RabbitMQ三. RabbitMQ作用四. MQ产品对比五. 安装RabbitMQ1. 安装erlang2. 安装rabbitMQ3. 安装RabbitMQ管理界⾯4. 启动服务5. 访问界面6. 添加管理员用户7. 重新登录 一. MQ MQ( Message queue ), 从字⾯意思上看, 本质是个队列, FIFO 先⼊先出&#xff…...

借助 AI 工具,共享旅游-卡-项目助力年底增收攻略

年底了&#xff0c;大量的商家都在开始筹备搞活动&#xff0c;接下来的双十二、元旦、春节、开门红、寒假&#xff0c;各种活动&#xff0c;目的就是为了拉动新客户。 距离过年还有56 天&#xff0c;如何破局&#xff1f; 1、销售渠道 针对旅游卡项目&#xff0c;主要销售渠道…...

Docker Compose 和 Kubernetes 之间的区别?

一、简介&#x1f380; 1.1 Docker Compose Docker Compose 是 Docker 官方的开源项目&#xff0c;负责实现对 Docker 容器集群的快速编排&#xff0c;可以管理多个 Docker 容器组成一个应用。你只需定义一个 YAML 格式的配置文件 docker-compose.yml &#xff0c;即可创建并…...

node.js常用的模块和中间件?

‌Node.js常用的模块和中间件包括以下几种‌&#xff1a; ‌Express‌&#xff1a;Express是一个灵活的Node.js web应用框架&#xff0c;提供了丰富的API来处理HTTP请求和响应。它支持中间件系统&#xff0c;可以轻松地添加各种功能&#xff0c;如路由、模板引擎、静态文件服务…...

Llama模型分布式训练(微调)

1 常见大模型 1.1 参数量对照表 模型参数量发布时间训练的显存需求VGG-19143.68M2014~5 GB&#xff08;单 224x224 图像&#xff0c;batch_size32&#xff09;ResNet-15260.19M2015~7 GB&#xff08;单 224x224 图像&#xff0c;batch_size32&#xff09;GPT-2 117M117M2019~…...

Matlab模块From Workspace使用数据类型说明

Matlab原文连接&#xff1a;Load Data Using the From Workspace Block 模型&#xff1a; 从信号来源的数据&#xff1a; timeseries 数据&#xff1a; sampleTime 0.01; numSteps 1001;time sampleTime*[0:(numSteps-1)]; time time;data sin(2*pi/3*time);simin time…...

LangChain学习笔记(一)-LangChain简介

LangChain学习笔记&#xff08;一&#xff09;-LangChain简介 langChain是一个人工智能大语言模型的开发框架&#xff0c;主要构成为下图。 ​ ​ 一、核心模块 &#xff08;一&#xff09;模型I/O模块 负责与现有大模型进行交互&#xff0c;由三部分组成&#xff1a; 提…...

k8s,声明式API对象理解

命令式API 比如&#xff1a; 先kubectl create&#xff0c;再replace的操作&#xff0c;我们称为命令式配置文件操作 kubectl replace的执行过程&#xff0c;是使用新的YAML文件中的API对象&#xff0c;替换原有的API对象&#xff1b;而kubectl apply&#xff0c;则是执行了一…...

KubeBlocks v0.9.2发布啦!支持容器镜像滚动更新、MySQL支持Jemalloc...快来升级体验更多新功能!

KubeBlocks v0.9.2 正式发布啦&#xff01;本次发布包含了一些新功能、关键的错误修复以及各种改进。以下是详细的更新内容。 升级文档 v0.9.2 升级方式与 v0.9.1 相同&#xff0c;替换版本即可哦&#xff5e; https://kubeblocks.io/docs/release-0.9/user_docs/upgrade/up…...

Linux-虚拟环境

文章目录 一. 虚拟机二. 虚拟化软件三. VMware WorkStation四. 安装CentOS操作系统五. 在VMware中导入CentOS虚拟机六. 远程连接Linux系统1. Finalshell安装2. 虚拟机网络配置3. 连接到Linux系统 七. 虚拟机快照 一. 虚拟机 借助虚拟化技术&#xff0c;我们可以在系统中&#…...

window系统下的git怎么在黑窗口配置代理

在Windows系统下&#xff0c;通过黑窗口&#xff08;命令行界面&#xff09;配置Git代理主要有两种方式&#xff1a;配置HTTP代理和配置SOCKS5代理。以下是具体的步骤&#xff1a; 配置HTTP代理 临时代理设置&#xff08;仅对当前命令行会话有效&#xff09;&#xff1a; set …...

网络和通信详解

一、Java 网络编程基础 IP 地址和端口号 IP 地址&#xff1a; IP 地址是互联网协议地址&#xff0c;用于标识网络中的设备。在 Java 中&#xff0c;InetAddress类是用于表示 IP 地址的主要类。例如&#xff0c;InetAddress.getByName("www.example.com")可以获取指定…...

网络安全框架及模型-PPDR模型

网络安全框架及模型-PPDR模型 概述: 为了有效应对不断变化的网络安全环境,人们意识到需要一种综合性的方法来管理和保护网络安全。因此,PPDR模型应运而生。它将策略、防护、检测和响应四个要素结合起来,提供了一个全面的框架来处理网络安全问题。 工作原理: PPDR模型的…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...

规则与人性的天平——由高考迟到事件引发的思考

当那位身着校服的考生在考场关闭1分钟后狂奔而至&#xff0c;他涨红的脸上写满绝望。铁门内秒针划过的弧度&#xff0c;成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定"&#xff0c;构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...