C++ 标准库 书籍学习记录笔记 第5章

5.3 迭代器 

  • 前置式递增比后置式递增效率更高,因为后者需要一个额外的临时对象,因为他需要存储一个迭代器原本的位置并将其进行返还,因此最好使用++pos,而不是pos++;

5.3.1 关联式容器的运用实例

  • 修改map默认的递增的方式,将内部排序修改为 递减方式
  •     std::map<int,int,std::greater<int>>map{};
  • greater是一个预先定义的仿函数
  • 关联式容器使用自己的默认规则进行元素位置的存放,因此相较于序列式容器取消了push_back()和push_front()函数
  • std::greater - C++中文 - API参考文档
#include <list>
#include <iostream>
#include <set>
#include <map>int main(){std::map<int,int,std::greater<int>>map{};map.insert(std::make_pair(1,1));map.insert(std::make_pair(2,2));map.insert(std::make_pair(3,3));map.insert(std::make_pair(4,4));for (auto temp=map.begin();temp!=map.end();++temp) {std::cout << temp->first << " " << temp->second << std::endl;}
}
  • multimap包含在map头文件内部,允许key和value是1对多的关系
#include <list>
#include <iostream>
#include <set>
#include <map>int main(){std::multimap<int,int,std::greater<int>>map{};map.insert(std::make_pair(1,1));map.insert(std::make_pair(1,1));map.insert(std::make_pair(1,1));map.insert(std::make_pair(1,1));map.insert(std::make_pair(2,2));map.insert(std::make_pair(3,3));map.insert(std::make_pair(4,4));for (auto temp=map.begin();temp!=map.end();++temp) {std::cout << temp->first << " " << temp->second << std::endl;}
}
  • 迭代器访问 元素的时候,可以使用 迭代器->first  或者  (*迭代器).first 使用*解除引用,再对元素进行访问
  • 类名 变量名;将创建一个对象将其存储在栈上,使用 变量名.成员  进行使用
  • 类名 变量名 = new 类名();  将创建一个对象将其存储在堆上,使用 变量名->成员  进行使用
  • map 键值/实值 所形成的群集中,如果所有的键值是唯一的,将其作为一个关联式数组;这里想表达的意思是我们可以像使用数组一样进行元素的访问,数组通过数组下标访问对应的数值,map可以通过指定key,访问对应的value。通过map[key]访问对应的数值

5.3.2 迭代器分类

  • 双向迭代器 Bidirectional iterator:双向行进,采用递增进行前进运算,使用递减进行后退运算,list、set、multiset、map和undered_map 都使用这个迭代器
  • 随机存储迭代器Random access iterator:在双向迭代器的基础上还具备了随机访问的特性,因此可以对迭代器增加或者减少一个偏移量,处理迭代器之间的距离,或者使用<和>之类的relational相对关系的操作符来比较两个迭代器。vector、deque和string均采用此迭代器
  • 尽量使用 != 这个的适配性更好,但是如果pos位于了end的后面,发生错误很难发现
    for(pos = coll.begin();pos != coll.end();++pos){}operator !=for(pos = coll.begin();pos < coll.end();++pos){}//operator < Random access iterator

5.4 算法

  • 算法不是容器类别的成员函数,而是搭配迭代器使用的全局函数,采用的是泛型函数编程的思维,数据和操作进行分离

5.4.2 处理多个区间

  • copy将第一区间的数据拷贝到目标区域,第一区间的起点和第一区间的终点确定了第一区间的元素的数量,因此第二区间只需要提供一个起点即可。
  • 但是copy函数使用的是覆写操作,不是插入操作,因此需要第二区间具备足够的内存空间,如下例子所示,会产生未定义的行为
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>int main(){std::list<int>coll1;std::vector<int>coll2;for (int i = 1; i <= 9; ++i) {coll1.push_back(i);}std::copy(coll1.begin(),coll1.end(),coll2.begin());
}
  • 对上述错误代码的修改:1,确认目标区域具备足够的内存;2,采用insert iterator
    std::list<int>coll1;std::vector<int>coll2;for (int i = 1; i <= 9; ++i) {coll1.push_back(i);}coll2.resize(coll1.size());std::copy(coll1.begin(),coll1.end(),coll2.begin());

5.5 迭代器配接器

  • Insert iterator 安插型迭代器
  • Stream iterator 流迭代器
  • reverse iterator 逆向迭代器

Insert iterator 安插型迭代器

  • 采用安插方式而不是覆写的方式运作,解决目标区域不足的问题  3种方式
  • Back inserters 安插在容器的最尾端:内部调用push_back() 采用追加的操作,只能适用于具备push_back()成员函数的容器中  适用于vector list deque
  •     std::copy(coll1.begin(),coll1.end(),std::back_inserter(coll2));
  • Front inserters 安插在容器最前端,内部调用的是push_front() ,这种操作会逆转被插元素的次序,比如插入1 再次插入 2,输出的时候2会在1 的前面打印输出  这个适用于 list 和 deque
  •     std::copy(coll1.begin(),coll1.end(),std::insert_iterator<>(coll2));
  • General inserters一般性安插器: 将元素插入到初始化时接受的第二个参数指向的前方。内部调用的是insert函数,并按照新值和新的位置作为参数。适用于关联式容器

 流迭代器

  • stream iterator是一种用来读取stream流的迭代器。提供了必要的抽象性,使得键盘的输入像一个群集,使得程序员可以从中读取内容,也可以把算法的输出重新导向某个文件或者屏幕
  • 代码没有跑通
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;
int main(){std::vector<std::string>coll{};copy(std::istream_iterator<string>(cin),istream_iterator<string>(),back_inserter(coll));sort(coll.begin(),coll.end());unique_copy(coll.begin(),coll.end(),ostream_iterator<string>(cout,"\n"));
}

5.5.3 reverse iterators 逆向迭代器

  • coll.rbegin()指向的是逆向遍历的起点,也就是先前的end()-1 的位置 

5.6.1 移除元素

  •  remove移除元素,是使用删除元素位置之后的元素对删除位置上的元素进行替代,不会是将其所有的3全部删除
  • 但是群集末尾未被覆盖的元素原封不动,但是从逻辑层面上讲,他们已经不属于这个群集了
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;
int main(){std::list<int>coll{};for(int i=1;i<=6;i++){coll.push_back(i);coll.push_front(i);}std::cout << "pre: ";copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));std::cout << std::endl;std::remove(coll.begin(),coll.end(),3);std::cout << "post: ";copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));std::cout << std::endl;
}
  • pre: 6 5 4 3 2 1 1 2 3 4 5 6
  • post: 6 5 4 2 1 1 2 4 5 6 5 6 
  • 实际上 算法会产生一个新的终点,需要更新新的终点的位置,获得新的区间,也就是缩减元素之后的容器的大小,亦或是删除元素的个数

 改进如下

  •     std::list<int>::iterator end = std::remove(coll.begin(),coll.end(),3);
  • 这个end也就是经过删除之后逻辑上新的终点
  • 或者获取徐亚删除的元素的个数,利用distance函数,返回两个迭代器之间的距离
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;
int main(){std::list<int>coll{};for(int i=1;i<=6;i++){coll.push_back(i);coll.push_front(i);}std::cout << "pre: ";copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));std::cout << std::endl;std::list<int>::iterator end = std::remove(coll.begin(),coll.end(),3);std::cout << "post: ";copy(coll.begin(),end,ostream_iterator<int>(cout," "));std::cout << std::endl;std::cout << "number of removed elements: "<< std::distance(end,coll.end()) << std::endl;coll.erase(end,coll.end());copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));std::cout << std::endl;
}

5.6.2 更易型算法和关联式容器

  • 更易型算法是指 移除、重排、修改元素的算法,这些算法不适用于关联型算法,因为这些操作会修改位置上的数值,破坏排序
  • 因此,关联式容器的所有迭代器都被声明为指向常量
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;
int main(){set<int>coll{};for (int i = 0; i <= 9; ++i) {coll.insert(i);}copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));std::cout << std::endl;int num = coll.erase(3);cout << "number os removed elements:" << num << std::endl;copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
}

5.6.3 算法 VS 成员函数

  • 如果容器提供了功能相似但是性能更佳的成员函数,优先使用成员函数
  • 成员函数 对其进行了优化,相较于函数功能相似的算法

  • 成员函数 remove(coll.begin(),coll.end(),4)
  • 算法:    coll.remove(4);
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;
int main(){list<int>coll{};for (int i = 1; i <= 6; ++i) {coll.push_front(i);coll.push_back(i);}coll.erase(remove(coll.begin(),coll.end(),3),coll.end());coll.remove(4);
}

5.8.1 以函数作为算法的参数

  • 算法接收用户定义的辅助性函数 ,在算法的内部被调用
  • for_each函数对coll的begin到end区间内的每一个元素都调用print函数进行输出
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;void print(int elem){std::cout << elem << " ";
}
int main(){std::vector<int>coll{};for (int i = 1; i <= 9; ++i) {coll.push_back(i);}std::for_each(coll.begin(),coll.end(),print);
}
  • 算法以🌲种态度来面对辅助函数,1,将其视为可有可无;2,视为必要;
  • 利用他们指定搜寻的规则、排序的规则或者定义某种操作,从而将某个容器内 的元素转换到另外一个容器
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;void print(int elem){std::cout << elem << " ";
}int square(int value){return value*value;
}
int main(){std::set<int>coll{};std::vector<int>coll2{};for (int i = 1; i <= 9; ++i) {coll.insert(i);}std::transform(coll.begin(),coll.end(),std::back_inserter(coll2),square);std::for_each(coll2.begin(),coll2.end(),print);
}

5.8.2 判断式

  • 潘端师就是返还结果是布尔数值的函数,常用于指定排序准则和搜寻准则,可能有一个或者两个操作数
  • 判断式 对于相同的输入返还相同的输出结果,且程序执行不可以改变内部状态 

一元判断式

 二元判断式

 

5.9 仿函数

  • 泛型编程强大威力和存粹抽象的一个例证。仿函数就是行为像函数,比如定义一个对象,他具备类似函数的一些特性,就可以当做函数来使用;比如使用小括号传递参数,如果指望定义的对象也可以实现 使用小括号传递参数,比如定义operator()   
#include <list>
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>using namespace std;class X{
public:int operator()(int v1,int v2)const;
};
int X::operator()(int v1, int v2) const {std::cout << v1 << " "<< v2<< std::endl;
}
int main(){X fo;fo(4,5);fo.operator()(4,5);
}
class PrintInt{
public:void operator()(int elem)const{std::cout << elem << std::endl;}
};
int main(){std::vector<int>coll{};for (int i = 1; i <= 6; ++i) {coll.push_back(i);}std::for_each(coll.begin(),coll.end(),PrintInt());
}

 

void add10(int & elem){elem += 10;
}
int main(){std::vector<int>coll{};for (int i = 1; i <= 6; ++i) {coll.push_back(i);}for_each(coll.begin(),coll.end(),add10);std::for_each(coll.begin(),coll.end(),PrintInt());
}
  • 如果需要数个不同的固定数值  而且他们在编译期 都已经确认,可以使用template 
  • 使用模板传参,需要在函数被调用之前将数值传递给函数 
  •  具体的代码如下面所示,    for_each(coll.begin(),coll.end(),AddValue(10));这种方式,使用AddValue(10)生成一个AddValue的组件,并且赋予了初值为10,构造函数就会把10保存在成员theValue中,在for_each之内,针对coll的每一个元素调用 () ,实际上就是对传入的那个AddValue对象 暂时调用 operator()操作,并以容器的元素作为参数
class AddValue{
private:int theValue;
public:AddValue(int v):theValue(v){};void operator()(int& elem)const{elem += theValue;}
};
class PrintInt{
public:void operator()(int elem)const{std::cout << elem << " ";}
};
int main(){std::vector<int>coll{};for (int i = 1; i <= 6; ++i) {coll.push_back(i);}for_each(coll.begin(),coll.end(),AddValue(10));std::for_each(coll.begin(),coll.end(),PrintInt());std::cout << std::endl;for_each(coll.begin(),coll.end(),AddValue(*coll.begin()));std::for_each(coll.begin(),coll.end(),PrintInt());
}
  •      for_each(coll.begin(),coll.end(),AddValue(*coll.begin()+5));这种方式,传入的参数
  • 使用这个技术就可以实现先前所说的 一个函数,两种状态的问题,用两个不同的仿函数实现
class AddValue{
private:int theValue;
public:AddValue(int v):theValue(v){};void operator()(int& elem)const{elem += theValue;}
};
class PrintInt{
public:void operator()(int elem)const{std::cout << elem << " ";}
};
int main(){std::vector<int>coll{};for (int i = 1; i <= 6; ++i) {coll.push_back(i);}AddValue addx(4);for_each(coll.begin(),coll.end(),addx);std::for_each(coll.begin(),coll.end(),PrintInt());std::cout << std::endl;AddValue addy(5);for_each(coll.begin(),coll.end(),addy);std::for_each(coll.begin(),coll.end(),PrintInt());
}

 5.9.2 预先定义的仿函数

  • C++标准库 包含了一些预定义的仿函数 涵盖了部分的基础运算
  • 比如排序默认的排序是从小到大,也就是operator < 的缺省排序准则就是 less<>
  • 默认的 std::set<int>coll  ->  set<int,less<int>>coll
  • 反向排列   set<int,greater<int>>coll

  • negate<int>()  将传入的int数值设置为 负数
  • transform()算法 将第一群集的所有元素处理之后转移到第二群集,如果第二群集的起始地址是自身,就相当于对第一群集的元素进行操作覆盖
  • transform的另外一种形式,按照某种特定的运算,将两个群集内的元素处理之后将其结果写入到第三群集;如下所示,设定 第一群集、第二群集 将两个群集的元素进行计算,将结果写回到第三群集

 

class PrintInt{
public:void operator()(int elem)const{std::cout << elem << " ";}
};
int main(){std::set<int,std::greater<int>>coll1;std::deque<int>coll2;for (int i = 1; i <= 9; ++i) {coll1.insert(i);}std::for_each(coll1.begin(),coll1.end(),PrintInt());transform(coll1.begin(),coll1.end(), //sourceback_inserter(coll2), //destinationbind2nd(multiplies<int>(),10)); //operationstd::cout << std::endl;std::for_each(coll2.begin(),coll2.end(),PrintInt());//replace value equals to 70 with 42replace_if(coll2.begin(),coll2.end(), //rangebind2nd(equal_to<int>(),70), //replace criterion42); //new valuestd::cout << std::endl;std::for_each(coll2.begin(),coll2.end(),PrintInt());//remove all elements with values less than 50coll2.erase(remove_if(coll2.begin(),coll2.end(), //rangebind2nd(less<int>(),50)), //remove criterioncoll2.end());std::cout << std::endl;std::for_each(coll2.begin(),coll2.end(),PrintInt());
  •     transform(coll1.begin(),coll1.end(), //source
                  back_inserter(coll2), //destination
                  bind2nd(multiplies<int>(),10)); //operation
  • bind2nd 就是  进行multiplies<int>()运算的时候,将源群集的元素作为第一参数,将10 作为第二参数

  • 所有的仿函数通常都声明为inline,一方面使用类似函数的表示法或者抽象性,一方面又可以获得出色的效能
  • 还有一些仿函数可以调用群集内的每个元素的成员函数 

 

 

 

 

  • 智能指针:是一种对象,有着类似指针的接口,但是内部实现了一些额外的检查和处理工作 

 

 

 

 

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

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

相关文章

中科大 计算机网络15 DNS域名解析系统

DNS的必要性 DNS域名解析系统&#xff1a;不是直接给人使用的&#xff0c;而是给其他应用使用的 域名到IP地址的转换【使用&#xff1a;web应用&#xff0c;FTP应用。。。】 在应用层跑的基础设施&#xff0c;为其他应用而使用 网络层的工作的设备使用IP地址&#xff0c;用来…

面试题目汇总

1&#xff0c;for循环的时间复杂度 两层for循环 第二层中 的循环变量继承与上层变量时间复杂度是O(n^2)for循环时间复杂度算法理解_bingkxin的专栏-CSDN博客_for循环时间复杂度 for(int i0;i<N;i) {for(int ji;j<N;j){//此处运行次数:NN-1N-2...1123...NN(N1)/2} } for(…

C++基础1 数据类型 常量

使用Dev CPP作为编程环境、 注意dev cpp5.4.0没有格式化代码功能&#xff0c;不要再设置了 设置的常用快捷键 CtrE:多行注释 CtrlShiftE:取消多行注释 CtrlZ&#xff1a;撤销 CtrlShiftZ:取消撤销 CtrlL:折叠函数 CtrlShifL:取消折叠函数 设置Dev Cpp Dev C初始化&#xf…

amd核芯显卡控制面板自定义分辨率_显卡天梯图2020最新版 2020年5月显卡排行榜天梯图...

转眼五月份就到来了&#xff0c;最近各大厂商可谓是你方唱罢我登场啊&#xff0c;发布会一场接着一场&#xff0c;新品和概念产品等一个接着一个的放出&#xff0c;我相信很多小伙伴们都迫不及待了&#xff01;~下面和小编一起来看看吧。2020年5月显卡排行榜天梯图&#xff1a;…

Python学习9 面向对象 类和对象

面向对象和面向过程 类和对象 类的设计 类的创建 self:相当于当前对象&#xff1b;类似于Java中的this 类的创建和使用&#xff1a; #类的命名&#xff1a;每个单词首字母大写 class Dog:#属性name dogage 11#方法def eat(self):print(eat rice!)dog Dog() print(dog.n…

刷机提示图像和设备不匹配_安卓5.0升级失败如何解决 安卓5.0刷机失败解决方法介绍【教程】...

安卓5.0升级失败怎么办?安卓5.0刷机失败急救方法?谷歌发布了适用于Nexus系列的Android 5.0系统&#xff0c;但是&#xff0c;刷安卓5.0系统时遇到system.img系统镜像找不到的错误提示是怎么回事?谷歌终于发布了适用于Nexus系列的Android 5.0底包和OTA推送&#xff0c;不过第…

华为模拟器eNSP1

eNSP介绍 网络仿真工具平台 路由器AR

postman 不安全网站_接口工具分析(apipost、jmeter、postman)

一、接口都有哪些类型&#xff1f;接口一般分为两种&#xff1a;1.程序内部的接口 2.系统对外的接口系统对外的接口&#xff1a;比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把 数据库共享给你&#xff0c;他只能给你提供一个他们写好的方法来获取数据…

java-web前端 javascript

介绍 JavaScript是Web中一种功能强大的脚本语言&#xff0c;被设计为向 HTML 页面增加交互性&#xff0c;常用来为网页添加各式各样的动态功能&#xff0c;它不需要进行编译&#xff0c;直接嵌入在HTML页面中&#xff0c;就可以把静态的页面转变成支持用户交互并响应事件的动态…

C++笔试记录 2021年9月16日

1&#xff0c;函数模板缺省情况下都是内联的 需要进一步的学习 父类析构函数为非虚函数&#xff0c;子类为虚函数_zhl11a的专栏-CSDN博客_父类的析构函数是非虚的父类析构函数为非虚函数&#xff0c;子类为虚函数 delete子类指针(指向这个子类对象)会调用父类的析构函数 #i…

clientdataset 过滤 in_江门马弗过滤科技有限公司

点击蓝字关注我们江门马弗过滤科技有限公司成立于 2020 年&#xff0c;公司位于江门市江海区高新技术开发区&#xff0c;注册资金 500 万&#xff0c;工厂面积约 5185 平方米。我们致力于重型汽车空气过滤器产品的专业制造与研发,为商用车辆及工程车辆等提供过滤系统解决方案的…

java-web前端 CSS

CSS介绍 CSS 指的是层叠样式表* (Cascading Style Sheets), 描述了如何在屏幕、纸张或其他媒体上显示 HTML 元素,节省了大量工作&#xff0c;并且可以同时控制多张网页的布局 外部样式表存储在 CSS 文件中 CSS&#xff1a;也称级联样式表。 CSS语法 选择器指向您需要设置样式…

c++网吧计费系统_云游戏火了,中国14万家网吧走向何处?

日前微软与谷歌两大科技巨头纷纷宣布其在云游戏布局的最新进展&#xff0c;一时间云游戏成为游戏圈的热门词汇。作为云游戏一大落地场景&#xff0c;网吧这一发展了二十余年的产业&#xff0c;又将迎来新的变量。一些观点认为云游戏将大幅降低网吧的硬件成本&#xff0c;解决网…

Python学习10 内置属性 对象属性 类属性 私有属性 私有方法 对象方法 类方法 静态方法

内置属性 创建类时系统自动创建的属性 # 内置属性&#xff1a;dir(对象)&#xff0c;列出所有的内置属性 class Person(object):Person类1# Person类2__slots__ (name, age)def __init__(self, name, age):self.name nameself.age agedef eat(self):print("eat!!!…

fastreport 上一行_创业天下全球总裁袁丽军一行莅临平川区 电商农特产扶贫展馆考察指导工作...

6 月12 日&#xff0c;创业天下全球总裁袁丽军带领考察组一行来平川区电商农特产扶贫展馆指导电商工作。区商务局局长冯月莉、区电子商务服务中心主任李守虎陪同考察。考察中&#xff0c;袁丽军一行就我区电商农特产扶贫展馆工作开展情况、平台运营情况、物流配送、产品商标注册…

滴滴笔试准备 项目分配利益最大化

思路&#xff1a;求取每一列的最大数值之和 #include <iostream> #include <vector>int row,column;int main(){std::cin >> row >> column;std::vector<std::vector<int>>input(row, std::vector<int>(column, 0));for (int i 0; …

Java web后端5 JSP技术

JSP概述 HTML代码与Java代码共同存在 浏览器中显示 启动Tomcat 浏览器访问&#xff1a;http://localhost:8083/JSPWeb_war_exploded/hello.jsp <%--Created by IntelliJ IDEA.User: DQDate: 2021/10/20Time: 9:30To change this template use File | Settings | File T…

listview bcb 行的颜色_文明交通安全行手抄报简单又漂亮

在生活中我们要特别注意交通安全&#xff0c;因为生命是宝贵的。全国交通安全日将至&#xff0c;下面小编给大家准备了文明交通安全行手抄报&#xff0c;一起来学习交通安全知识吧!文明交通安全行手抄报交通安全常识出家门&#xff0c;路边走&#xff0c;交通法规要遵守;过马路…

小米C++开发 面试 准备阶段和部分真题

真题 C 函数指针和指针函数的区别 o(╥﹏╥)o堆和栈的区别函数重载&#xff1f;为什么返回值不可以区分函数重载&#xff1f;o(╥﹏╥)o封装、继承和多态的定义&#xff0c;自己描述一下这三者的区别和联系。多态的构成(应该是想听虚函数&#xff0c;当时没有想到 o(╥﹏╥…

电脑屏保海底世界_水下栖息地:人类能否在海洋中居住?真的有人住在海底吗?...

慧缘开运讲坛&#xff1a;真的有人住在海底吗&#xff1f;对于这个问题&#xff0c;你肯定首先会想到美人鱼&#xff0c;对于未知的事物&#xff0c;我们并没有证据证明它们的存在。人类如何居住海底呢&#xff1f;那首先需要一个密闭的生态环境供进入海底的人生活。我们可以称…