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

[STL-list]介绍、与vector的对比、模拟实现的迭代器问题

一、list使用介绍

  1.  list的底层是带头双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
  2. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好
  3. list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;
常用接口:

构造函数:

构造函数接口说明
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list()构造空的list
list (const list& x)拷贝构造函数
list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list

代码演示:

    list<int> l1;                         // 构造空的l1list<int> l2(4, 100);                 // l2中放4个值为100的元素list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左闭右开的区间构造l3list<int> l4(l3);                    // 用l3拷贝构造l4// 以数组为迭代器区间构造l5int array[] = { 16,2,77,29 };list<int> l5(array, array + sizeof(array) / sizeof(int));// 列表格式初始化C++11list<int> l6{ 1,2,3,4,5 };

list iterator的使用

对于迭代器的使用我们可以把它理解为一个指针,指向ist的某个节点

函数声明接口说明
begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin+ rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置reverse_iterator,即begin位置

【注意】
1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

代码演示:

    list<int> lt(4, 100);  list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}       cout << endl;// C++11范围for的方式遍历for (auto& e : lt)cout << e << " ";cout << endl;

list modifiers

函数声明接口说明
push_front在list首元素前插入值为val的元素
pop_front删除list中第一个元素
push_back在list尾部插入值为val的元素
pop_back删除list中最后一个元素
insert在list position 位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素
clear清空list中的有效元素

代码演示:

void TestList1()
{int array[] = { 1, 2, 3 };list<int> L(array, array + sizeof(array) / sizeof(array[0]));// 在list的尾部插入4,头部插入0L.push_back(4);L.push_front(0);// 删除list尾部节点和头部节点L.pop_back();L.pop_front();
}// insert /erase 
void TestList2()
{int array1[] = { 1, 2, 3 };list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));// 获取链表中第二个节点auto pos = ++L.begin();cout << *pos << endl;// 在pos前插入值为4的元素L.insert(pos, 4);// 在pos前插入5个值为5的元素L.insert(pos, 5, 5);// 在pos前插入[v.begin(), v.end)区间中的元素vector<int> v{ 7, 8, 9 };L.insert(pos, v.begin(), v.end());// 删除pos位置上的元素L.erase(pos);// 删除list中[begin, end)区间中的元素,即删除list中的所有元素L.erase(L.begin(), L.end());
}// resize/swap/clear
void TestList3()
{// 用数组来构造listint array1[] = { 1, 2, 3 };list<int> l1(array1, array1 + sizeof(array1) / sizeof(array1[0]));// 交换l1和l2中的元素list<int> l2;l1.swap(l2);// 将l2中的元素清空l2.clear();cout << l2.size() << endl;
}

其他接口

二、与vector对比

vectorlist



动态顺序表,一段连续空间带头结点的双向循环链表


访
支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素效率O(N)




任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不需要搬移元素,时间复杂度为
O(1)




底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低


原生态指针对原生态指针(节点指针)进行封装




在插入元素时,要给所有的迭代器重新赋值,因为插入
元素有可能会导致重新扩容,致使原来迭代器失效,删
除时,当前迭代器需要重新赋值否则会失效
插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使


需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

vector与list排序效率对比:

void test_op1()
{srand(time(0));const int N = 1000000;list<int> lt1;list<int> lt2;vector<int> v;for (int i = 0; i < N; ++i){auto e = rand() + i;lt1.push_back(e);v.push_back(e);}int begin1 = clock();// sort(v.begin(), v.end());int end1 = clock();int begin2 = clock();lt1.sort();int end2 = clock();printf("vector sort:%d\n", end1 - begin1);printf("list sort:%d\n", end2 - begin2);
}

 

void test_op2()
{srand(time(0));const int N = 1000000;list<int> lt1;list<int> lt2;for (int i = 0; i < N; ++i){auto e = rand();lt1.push_back(e);lt2.push_back(e);}int begin1 = clock();// vectorvector<int> v(lt2.begin(), lt2.end());// sort(v.begin(), v.end());// lt2lt2.assign(v.begin(), v.end());int end1 = clock();int begin2 = clock();lt1.sort();int end2 = clock();printf("list copy vector sort copy list sort:%d\n", end1 - begin1);printf("list sort:%d\n", end2 - begin2);
}

可见list的排序效率是非常低的,甚至将list的数据导入vector中排完序在导回来的效率都比直接在list中排序的效率快,这是因为list不支持下标随机访问,只能依靠迭代器迭代到指定位置访问,而排序过程中避免不了需要访问大量中间元素,所以list并不适合对数据进行排序

三、list迭代器问题

链表节点与链表结构

节点包含三部分:前驱指针、后驱指针、数据。list封装了头节点的指针,可以根据该指针对后续节点进行遍历

    template<class T>struct ListNode{ListNode* _next;ListNode* _prev;T _data;//节点的构造函数ListNode(const T& x = T()):_next(nullptr),_prev(nullptr),_data(x){}};template<class T>class list{void Empty_Init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}//构造函数list(){Empty_Init();}private:Node* _head;size_t _size;};
如何设定list迭代器

        在string与vector的模拟实现中,迭代器使用的都是原生指针T*,这是因为原生指针可以满足迭代器的要求,++可以指向下一个元素,解引用可以访问该元素,他们可以使用原生指针的根本原因是他们储存数据的结构都是连续的物理地址。

        在list中原生指针Node*不能满足我们的要求,因为list的节点都是依靠指针连接起来的,其物理地址并不是连续的,++指向的并不是下一个元素,而是指向了跳过了一个Node的大小的的地址,并且迭代器希望解引用直接可以访问节点中的数据,而*(Node*)却是一个节点类型,所以在list中使用原生指针并不符合迭代器的要求。

         所以我们可以自己新建一个类,作为迭代器的类型,在其中封装了头节点,就可以访问该链表了,并且我们在该类中可以通过运算符重载改变++与解引用的行为,这样就可以使用迭代器访问链表数据了

    template<class T>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T> Self;Node* _node;ListIterator(Node* _node):_node(_node){}T& operator*(){return _node->_data;}//前置++Self& operator++(){_node = _node->_next;return *this;}//后置++Self operator++(int){Self tmp(_node);_node = _node->_next;return tmp;}};template<class T>class list{void Empty_Init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}//构造函数list(){Empty_Init();}iterator begin(){//隐式类型转换return _head->_next;}iterator end(){//隐式类型转换return _head;}private:Node* _head;size_t _size;};
完善迭代器功能  
operator->的重载

        但是上述代码具有一定的局限性,例如当T为一个结构体A时,*iterator返回的是结构体A,想要访问结构体中的数据还需要用 例如:*(it).a1,但是这样写有点多次一举,因为迭代器it本身就是指向节点的指针,访问数据可以直接使用 ->,例如:it->a1,所以我们还需要将->重载一下

  T* operator->(){//返回数据的地址return &_node->_data;}

结构体A存储在节点的_data中,这里返回了_data的地址,如果按照正常的思路进行访问,应该按照如下的方式:it.operator->()->_a1 应该是两个箭头,第一个箭头代表运算符的重载,第二个代表指针解引用访问数据。
但是编译器为了方便查看会进行优化,将两个箭头变成了一个箭头 it->_a1 ,这样直接可以访问

const迭代器

const的本质就是为了禁止对成员进行修改,所以我们只需要const迭代器只需要对非const迭代器稍加修改即可

    template<class T>struct ListConstIterator{typedef ListNode<T> Node;typedef ListConstIterator<T> Self;Node* _node;ListConstIterator(Node* _node):_node(_node){}const T& operator*(){return _node->_data;}const T* operator->(){return &_node->_data;}};

但是这样const迭代器与非const迭代器这两个类的重合度非常高,仅仅是函数返回值前是否加用const修饰的区别,所以我们可以利用模板

    typedef ListIterator<T,T&,T*> iterator;typedef ListIterator<T,const T&,const T*> const_iterator;---------------------------------template<class T,class Ref,class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* _node):_node(_node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}//前置++Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(_node);_node = _node->_next;return tmp;}};
完整代码:
#include<iostream>
using namespace std;
namespace zyq
{template<class T>struct ListNode{ListNode* _next;ListNode* _prev;T _data;ListNode(const T& x = T()):_next(nullptr),_prev(nullptr),_data(x){}};//template<class T>//struct ListIterator//{//	typedef ListNode<T> Node;//	typedef ListIterator<T> Self;//	Node* _node;//	ListIterator(Node* _node)//		:_node(_node)//	{}//	T& operator*()//	{//		return _node->_data;//	}//     T* operator->()//	{//		return &_node->_data;//	}//	//前置++//	Self& operator++()//	{//		_node = _node->_next;//		return *this;//	}//	Self operator++(int)//	{//		Self tmp(_node);//		_node = _node->_next;//		return tmp;//	}//	bool operator!=(const Self& it)//	{//		return !(_node == it._node);//	}//	bool operator==(const Self& it)//	{//		return _node == it._node;//	}//};//template<class T>//struct ListConstIterator//{//	typedef ListNode<T> Node;//	typedef ListConstIterator<T> Self;//	Node* _node;//	ListConstIterator(Node* _node)//		:_node(_node)//	{}//	const T& operator*()//	{//		return _node->_data;//	}//	const T* operator->()//	{//		return &_node->_data;//	}//	//前置++//	 Self& operator++()//	{//		_node = _node->_next;//		return *this;//	}//	Self operator++(int)//	{//		Self tmp(_node);//		_node = _node->_next;//		return tmp;//	}//	bool operator!=(const Self& it)//	{//		return !(_node == it._node);//	}//	bool operator==(const Self& it)//	{//		return _node == it._node;//	}//};template<class T,class Ref,class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* _node):_node(_node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}//前置++Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(_node);_node = _node->_next;return tmp;}bool operator!=(const Self& it){return !(_node == it._node);}bool operator==(const Self& it){return _node == it._node;}};template<class T>class list{public:typedef ListNode<T> Node;//typedef ListIterator<T> iterator;//typedef ListConstIterator<T> const_iterator;typedef ListIterator<T,T&,T*> iterator;typedef ListIterator<T,const T&,const T*> const_iterator;iterator begin(){//隐式类型转换return _head->_next;}iterator end(){//隐式类型转换return _head;}const_iterator begin() const{//隐式类型转换return _head->_next;}const_iterator end() const{//隐式类型转换return _head;}void Empty_Init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}//构造函数list(){Empty_Init();}//拷贝构造list(const list<T>& lt){Empty_Init();for (auto& e : lt){push_back(e);}}void swap(list<T> lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}//赋值运算符重载list<T>& operator=(list<T> lt){swap(lt);return *this;}~list(){iterator it = begin();while (it != end()){it=erase(it);}delete _head;_head = nullptr;}size_t size(){return _size;}/*void push_back(const T& x){Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;_size++;}*/void push_back(const T& x){insert(end()  , x);}void  push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void insert(iterator pos, const T& x){Node* newnode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;}iterator erase(iterator pos){Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;_size--;return next;}private:Node* _head;size_t _size;};template<class T>void PrintList(const list<T>& clt){typename list<T>::const_iterator it = clt.begin();while (it != clt.end()){cout << *it << " ";it++;}cout << endl;}void testlist1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";it++;}cout << endl;/*lt.push_back(9);lt.pop_front();*/PrintList(lt);list<int> lt1(lt);PrintList(lt1);list<int> lt2;lt2 = lt;PrintList(lt2);}struct A{int _a1;int _a2;A(int a1 = 0, int a2 = 0):_a1(a1), _a2(a2){}};void testlist2(){list<A> lt;lt.push_back({ 1,2 });lt.push_back(A(1,2));list<A>::iterator it = lt.begin();while (it != lt.end()){//cout << (*it)._a1 << " " << (*it)._a2 << " ";cout << it->_a1 << " " << it->_a2 << " ";it++;}cout << endl;}
}

相关文章:

[STL-list]介绍、与vector的对比、模拟实现的迭代器问题

一、list使用介绍 list的底层是带头双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一个元素。与其他的序列式容器相比(array&#xff0c;vector&#xff0c;deque)&#xff0c;list通常在任意位置进行…...

代码随想录-035期-算法训练营【博客笔记汇总表】

ヾ(◍∇◍)&#xff89;&#xff9e;加油~ 目录 00、说明 01、刷题网址 02、每日打卡任务 03、博客打卡笔记 01、数组 02、链表 03、哈希表 04、字符串 05、双指针法 06、栈与队列 07、二叉树 08、回溯算法 09、贪心算法 10、动态规划 11、单调栈 12、图论 04…...

postgresql数据库|数据整合的好工具--Oracle-fdw的部署和使用

概述 Oracle_fdw 是一种postgresql外部表插件&#xff0c;可以读取到Oracle上面的数据。是一种非常方便且常见的pg与Oracle的同步数据的方法 Oracle_fdw 适用场景&#xff1a; Oracle_fdw 是一个开源的 Foreign Data Wrapper (FDW)&#xff0c;主要用于在 PostgreSQL 数据库中…...

让php开发更优雅-Laravel篇

前言 随着开发经验的增加&#xff0c;也伴随团队开发的积累&#xff0c;规范开发显得越来越重要&#xff0c;本文给大家提供一些laravel开发的进阶思路和经验&#xff0c;让大家开发更加统一规范&#xff0c;代码看起来更加优雅。 1.更多使用第三方库。团队开发的时候&#xf…...

自动化测试之httprunner框架hook函数实操

本篇介绍httprunner中hook函数的使用&#xff0c;以及通过编程能力实现建设自动化测试更全面的场景覆盖 前置&#xff1a; 互联网时代让我们更快的学习到什么是Httprunner 正文&#xff1a; 经过上文了解到这个框架怎么使用之后&#xff0c;我们开始来探讨一下我们为什么要用…...

物联网实战--入门篇之(七)嵌入式-MQTT

目录 一、MQTT简介 二、MQTT使用方法 三、MQTT驱动设计 四、代码解析 五、使用过程 六、总结 一、MQTT简介 MQTT因为其轻量、高效和稳定的特点&#xff0c;特别适合作为物联网系统的数据传输协议&#xff0c;已经成为物联网事实上的通信标准了。关于协议的具体内容看看这…...

跑模型——labelme的json文件转成yolo使用的txt文件(语义分割)

前言 将labelme多边形标注的json文件转换成yolo使用的txt文件 import os import json import numpy as np from tqdm import tqdm#实现函数 def json2txt(path_json, path_txt): # 可修改生成格式with open(path_json, r) as path_json:jsonx json.load(path_json)with open…...

一个项目仿京东商场代码

git clone http://git.itcast.cn/heimaqianduan/erabbit-uni-app-vue3-ts.git...

计算机网络——WEB服务器编程实验

实验目的 1. 处理一个 http 请求 2. 接收并解析 http 请求 3. 从服务器文件系统中获得被请求的文件 4. 创建一个包括被请求的文件的 http 响应信息 5. 直接发送该信息到客户端 具体内容 一、C 程序来实现 web 服务器功能。 二、用 HTML 语言编写两个 HTML文件&#xff0c;并…...

蓝桥杯算法题:最大比例

题目描述&#xff1a; X星球的某个大奖赛设了 M 级奖励。 每个级别的奖金是一个正整数。 并且&#xff0c;相邻的两个级别间的比例是个固定值。 也就是说&#xff1a;所有级别的奖金数构成了一个等比数列。 比如&#xff1a;16,24,36,54&#xff0c;其等比值为&#xff1a;3/2。…...

【堡垒机】堡垒机的介绍

目前&#xff0c;常用的堡垒机有收费和开源两类。 收费的有行云管家、纽盾堡垒机&#xff1b; 开源的有jumpserver&#xff1b; 这几种各有各的优缺点&#xff0c;如何选择&#xff0c;大家可以根据实际场景来判断 什么是堡垒机 堡垒机&#xff0c;即在一个特定的网络环境下&…...

通过 ffmpeg命令行 调节视频播放速度

1. 仅调整视频速率 视频调速原理&#xff1a;修改视频的pts&#xff0c;dts # 可能会丢帧 ffmpeg -i input.mkv -an -filter:v "setpts0.5*PTS" output.mkv # 可用-r参数指定输出视频FPS以防止丢帧 ffmpeg -i input.mkv -an -r 60 -filter:v "setpts2.0*PTS&q…...

SQLite数据库在Linux系统上的使用

SQLite是一个轻量级的数据库解决方案&#xff0c;它是一个嵌入式的数据库管理系统。SQLite的特点是无需独立的服务器进程&#xff0c;可以直接嵌入到使用它的应用程序中。由于其配置简单、支持跨平台、服务器零管理&#xff0c;以及不需要复杂的设置和操作&#xff0c;SQLite非…...

Spring中依赖注入的方法有几种,分别是什么?

依赖注入的目的&#xff1a; 都是为了减少对象之间的紧密耦合 1. 构造函数注入&#xff1a;通过在类的构造函数中接受依赖对象作为参数&#xff0c;Spring在创建对象时将依赖注入。 2. Setter方法注入&#xff1a;在类中提供setter方法&#xff0c;Spring通过调用这些setter方法…...

【面试精讲】MyBatis设计模式及源码分析,MyBatis设计模式实现原理

【面试精讲】MyBatis设计模式及源码分析&#xff0c;MyBatis设计模式实现原理 目录 本文导读 一、MyBatis中运用的设计模式详解 1. 工厂模式&#xff08;Factory Pattern&#xff09; 2. 单例模式&#xff08;Singleton Pattern&#xff09; 3. 建造者模式&#xff08;Bu…...

Acrel-1000DP光伏监控系统在尚雷仕(湖北)健康科技有限公司5.98MW分布式光伏10KV并网系统的应用

摘 要&#xff1a;分布式光伏发电特指在用户场地附近建设&#xff0c;运行方式多为自发自用&#xff0c;余电上网&#xff0c;部分项目采用全额上网模式。分布式光伏全额上网的优点是可以充分利用分布式光伏发电系统的发电量&#xff0c;提高分布式光伏发电系统的利用率。发展分…...

电脑远程控制esp32上的LED

1、思路整理 首先esp32需要连接上wifi 然后创建udp socket 接受udp数据 最后解析数据&#xff0c;控制LED 2、micropython代码实现 import network from socket import * from machine import Pin p2Pin(2,Pin.OUT)def do_connect(): #连接wifi wlan network.WLAN(network.…...

ARXML处理 - C#的解析代码(一)

目的 本文介绍通过AUTOSAR组织提供的xsd文件&#xff0c;自动生成对应的C#解析代码的框架。 自动生成方法&#xff1a;Microsoft SDKs\Windows\v7.0A\bin\xsd.exe 命令&#xff1a;xsd.exe AUTOSAR_4-0-3.xsd /c /l:CS /n:AUTOSAR4 AUTOSAR_4-0-3.xsd 是需要生成代码的xsd文…...

OJ 栓奶牛【C】【Python】【二分算法】

题目 算法思路 要求的距离在最近木桩与最远木桩相隔距离到零之间&#xff0c;所以是二分法 先取一个中间值&#xff0c;看按照这个中间值可以栓多少奶牛&#xff0c;再与输入奶牛数比较&#xff0c;如果大于等于&#xff0c;则增大距离&#xff0c;注意这里等于也是增大距离…...

Spring6-单元测试:JUnit

1. 概念 在进行单元测试时&#xff0c;特别是针对使用了Spring框架的应用程序&#xff0c;我们通常需要与Spring容器交互以获取被测试对象及其依赖。传统做法是在每个测试方法中手动创建Spring容器并从中获取所需的Bean。以下面的两行常见代码为例&#xff1a; ApplicationCo…...

ubuntu系统安装k8s1.28精简步骤

目录 一、规划二、环境准备2.1 配置apt仓库配置系统基本软件仓库配置k8s软件仓库安装常用软件包 2.2 修改静态ip、ntp时间同步、主机名、hosts文件、主机免密2.3 内核配置2.4 关闭防火墙、selinux、swap2.5 安装软件安装docker安装containerd安装k8s软件包 三、安装配置k8s3.1 …...

探讨Java和Go语言的缺点

文章目录 Java的缺点Go语言的缺点 通常我们都会讨论Java和GO的优点&#xff0c;如果讨论缺点往往能让人们更清楚优点的重要性&#xff0c;Java和Go的缺点或许往往就是对方优点所在 Java的缺点 冗长的代码&#xff1a;相较于一些现代编程语言&#xff0c;Java 的语法相对冗长&am…...

短剧在线搜索PHP网站源码

源码简介 短剧在线搜索PHP网站源码&#xff0c;自带本地数据库500数据&#xff0c;共有6000短剧视频&#xff0c;与短剧猫一样。 搭建环境 PHP 7.3 Mysql 5.6 安装教程 1.上传源码到网站目录中 2.修改【admin.php】中&#xff0c; $username ‘后台登录账号’; $passwor…...

Python map遍历

在Python中&#xff0c;map 函数是一个内置函数&#xff0c;它将指定的函数应用于给定序列&#xff08;如列表、元组等&#xff09;的每个项&#xff0c;并返回一个迭代器&#xff0c;该迭代器包含所有项经过指定函数处理后的结果。 ### map 函数的基本用法 map 函数的语法如…...

数据结构—红黑树

红黑树介绍 红黑树&#xff08;Red Black Tree&#xff09;是一种自平衡二叉查找树。由于其自平衡的特性&#xff0c;保证了最坏情形下在 O(logn) 时间复杂度内完成查找、增加、删除等操作&#xff0c;性能表现稳定。 在 JDK 中&#xff0c;TreeMap、TreeSet 以及 JDK1.8 的 …...

MES实施之工控机和电脑的选择

在MES项目实施过程中,经常会碰到工控机和电脑的选型问题,那么他们的区别是什么? 1、控机和普通个人电脑(PC)相比,具有以下几个区别: 1.运行环境不同:工控机通常需要在各种恶劣的工业环境中运行,如高温、高湿、强电磁干扰等,因此需要具有防尘、防水、抗干扰等特点。而…...

京东云服务器4核8G主机租用价格418元一年,1899元3年

京东云轻量云主机4核8G服务器租用价格418元一年&#xff0c;1899元3年&#xff0c;配置为&#xff1a;轻量云主机4C8G-180G SSD系统盘-5M带宽-500G月流量&#xff0c;京东云主机优惠活动 yunfuwuqiba.com/go/jd 可以查看京东云服务器详细配置和精准报价单&#xff0c;活动打开如…...

【多模态融合】MetaBEV 解决传感器故障 3D检测、BEV分割任务

前言 本文介绍多模态融合中&#xff0c;如何解决传感器故障问题&#xff1b;基于激光雷达和相机&#xff0c;融合为BEV特征&#xff0c;实现3D检测和BEV分割&#xff0c;提高系统容错性和稳定性。 会讲解论文整体思路、模型框架、论文核心点、损失函数、实验与测试效果等。 …...

[通俗易懂]《动手学强化学习》学习笔记1-第1章 初探强化学习

文章目录 前言第1章 初探强化学习1.1 简介序贯决策&#xff08;sequential decision making&#xff09;任务&#xff1a;强化学习与有监督学习或无监督学习的**区别**&#xff1a;改变未来 1.2 什么是强化学习环境交互与有监督学习的区别1&#xff1a;改变环境 &#xff08;说…...

centOS如何升级python

centOS下升级python版本的详细步骤 1、可利用linux自带下载工具wget下载&#xff0c;如下所示&#xff1a; 笔者安装的是最小centos系统&#xff0c;所以使用编译命令前&#xff0c;必须安装wget服务&#xff0c;读者如果安装的是界面centos系统&#xff0c;或者使用过编译工具…...