今日分享:C++ -- list 容器

😎【博客主页:你最爱的小傻瓜】😎

🤔【本文内容:C++ list容器 😍】🤔

---------------------------------------------------------------------------------------------------------------------------------

在 C++ 的数据江湖里,list 仿若一位灵动迅捷的暗卫。

它凭双向链表的隐秘锁链串联元素,从无空间局促的烦忧 —— 新增元素时,只需借由 push_front 或 push_back 施展暗劲,新的节点便如暗桩般悄然嵌入。那些静卧的元素,似暗格里的密信静待调阅,借迭代器轻轻游走,就能探寻到某一环的机密。

当你持迭代器之匕穿梭其中,恰似指尖拂过暗卫的锁链,每个元素皆有序排布,等你细究。若要对这锁链重构序列,sort 函数就是绝佳的秘使,瞬间就能让杂乱的节点规整得有条不紊。

无论是整数的密令、字符的暗语,还是自定义对象的机密情报,它都能妥善收纳,宛如一座随需而设的秘库,让各类数据在其中各就其位,等候编程者去调取探寻。

---------------------------------------------------------------------------------------------------------------------------------

1.list的介绍:

在之前,我们学习了vector这个容器,我们复习一下。它的优点是尾插尾删效率高支持随机访问。更详细的看我之前的博客链接:vector

今天我要分享的是list,它是以链表形式来实现的,并是环形双向链表(想要了解:顺序表和链表)。

list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

因为是链表所以不支持随机访问,只能是通过已知的位置迭代到想访问的位置。但在插入和删除这两个方面效率更高,由于它是指针的形式来去储存数据的,只要将邻近的指针跟它相链接就行,删除也类似。

forward_list 是单链表的形式,只能朝前迭代

list还需要一些额外的空间,以保存每个节点的相关联信息(前后指针)(对于存储类型较小元素的大list来说这可能是一个重要的因素,就是储存的数据多,但数据的大小比指针小)。

list 的使用:


1.构造:

构造函数声明功能说明
list()构造一个空的 list 容器,不包含任何元素
list (size_type n, const value_type& val = value_type())构造一个包含 n 个元素的 list,每个元素的值均为 val(默认值为元素类型的默认值)
list (const list& x)拷贝构造函数,构造一个与 x 完全相同的 list(包含相同的元素序列)
list (InputIterator first, InputIterator last)构造一个 list,包含迭代器区间 [first, last) 中的所有元素(将该区间内

无参构造:构造一个空 list

// list()
list<int> l;

构造并初始化 n 个 val

// list (size_type n, const value_type& val = value_type())
list<int> l(5, 10);

拷贝构造:用已存在的 list 构造新的 list

// list (const list& x);
list<int> l1{1, 2, 3};
list<int> l2(l1);

使用迭代器进行初始化构造:利用其他容器(或 list 自身部分范围)的迭代器构造新 list

// list (InputIterator first, InputIterator last);
// 示例1:用数组迭代器构造
int arr[] = {1, 2, 3, 4, 5};
list<int> l(arr, arr + 5);// 示例2:用其他 list 的迭代器构造
list<int> l1{1, 2, 3, 4, 5};
list<int> l2(l1.begin(), l1.end());

2.迭代器:

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

begin():返回指向容器第一个元素的可修改迭代器(iterator

end():返回指向容器最后一个元素后一位的可修改迭代器

用途:正向遍历并可修改元素

list<int> l{1,2,3};
for (auto it = l.begin(); it != l.end(); ++it) {*it += 10; // 修改元素:1→11,2→12,3→13
}

rbegin():返回指向容器最后一个元素的反向迭代器(reverse_iterator

rend():返回指向容器第一个元素前一位的反向迭代器

用途:反向遍历并可修改元素

list<int> l{1,2,3};
for (auto rit = l.rbegin(); rit != l.rend(); ++rit) {*rit *= 2; // 反向修改:3→6,2→4,1→2
}

3.列表元素访问:

函数声明

接口说明
front返回 list 的第一个节点中值的引用
back返回 list 的最后一个节点中值的引用

front() / back():获取头部 / 尾部元素:

list<int> l{1,2,3};
l.front() = 10; // 头部改为10:[10,2,3]
l.back() = 30;  // 尾部改为30:[10,2,30]

4.容量访问:

函数声明接口说明
empty检测 list 是否为空,是返回 true,否则返回 false
size返回 list 中有效节点的个数

empty():判断容器是否为空(无元素),返回 bool 值(true 表示空,false 表示非空)

list<int> l1; // 空列表
list<int> l2{1,2,3}; // 非空列表cout << (l1.empty() ? "l1为空" : "l1非空"); // 输出:l1为空
cout << (l2.empty() ? "l2为空" : "l2非空"); // 输出:l2非空

size():返回元素个数:

list<int> l{1,2,3};
cout << l.size(); // 输出:3

5.列表元素修改:

函数声明接口说明
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 中的有效元素

push_front(val):在头部添加元素

list<int> l{2,3};
l.push_front(1); // 结果:[1,2,3]

push_back(val):在尾部添加元素

list<int> l{1,2};
l.push_back(3); // 结果:[1,2,3]

insert(pos, val):在迭代器pos位置插入元素

list<int> l{1,3};
auto it = ++l.begin(); // 指向3的位置
l.insert(it, 2); // 结果:[1,2,3]

pop_front():删除头部元素

list<int> l{1,2,3};
l.pop_front(); // 结果:[2,3]

pop_back():删除尾部元素

list<int> l{1,2,3};
l.pop_back(); // 结果:[1,2]

remove(val):删除所有值为val的元素

list<int> l{1,2,2,3};
l.remove(2); // 结果:[1,3]

erase(pos):删除迭代器pos指向的元素

list<int> l{1,2,3};
auto it = ++l.begin(); // 指向2
l.erase(it); // 结果:[1,3]

clear():清空所有元素

list<int> l{1,2,3};
l.clear(); // 结果:空列表

6.操作:

函数声明接口说明
splice将元素从一个 list 转移到另一个 list(公有成员函数)
remove移除具有特定值的元素(公有成员函数)
remove_if移除满足特定条件的元素(公有成员函数模板)
unique移除重复的值(公有成员函数)
merge合并已排序的列表(公有成员函数)
sort对容器中的元素进行排序(公有成员函数)
reverse反转元素的顺序(公有成员函数)

splice(转移)

 list<int> l1 = {1, 2, 3};list<int> l2 = {4, 5, 6};auto it = l1.begin();advance(it, 1); // 让 it 指向 l1 中元素 2l1.splice(it, l2); // 将 l2 中所有元素转移到 l1 中 it 指向的位置前for (auto num : l1) {cout << num << " ";}cout << endl;// 此时 l1: 1, 4, 5, 6, 2, 3;l2 为空

remove/remove_if

list<int> l = {1, 2, 2, 3};l.remove(2); // 移除值为 2 的元素for (auto num : l) {cout << num << " ";}cout << endl; // 输出:1 3list<int> l = {1, 2, 3, 4, 5};// 移除大于 3 的元素l.remove_if(bind(greater<int>(), placeholders::_1, 3));for (auto num : l) {cout << num << " ";}cout << endl; // 输出:1 2 3

unique

 list<int> l = {1, 1, 2, 2, 3, 3};l.unique(); // 移除相邻的重复元素for (auto num : l) {cout << num << " ";}cout << endl; // 输出:1 2 3

merge

list<int> l1 = {1, 3, 5};list<int> l2 = {2, 4, 6};l1.merge(l2); // 合并两个已排序的 listfor (auto num : l1) {cout << num << " ";}cout << endl; // 输出:1 2 3 4 5 6

sort

list<int> l = {3, 1, 2};l.sort(); // 对 list 中的元素进行排序for (auto num : l) {cout << num << " ";}cout << endl; // 输出:1 2 3

reverse

 list<int> l = {1, 2, 3};l.reverse(); // 反转 list 中元素的顺序for (auto num : l) {cout << num << " ";}cout << endl; // 输出:3 2 1

一些小知识:

双向迭代器:可双向移动(支持++--),功能强于单向迭代器,继承单向迭代器操作,新增--(前置 / 后置),不支持随机访问(如+=n),典型容器像listmap/set

随机访问迭代器:支持任意位置跳转(随机访问),功能最强,继承双向迭代器操作,新增+=n-=n[]</>等关系运算,典型容器为vectordequearray

单向迭代器:仅能从容器到尾单向移动,支持读取(部分可修改),操作有++(前置 / 后置)、*(解引用读)、->,不支持--+=n等,典型容器如forward_listunordered_map/unordered_set

迭代器分类是对移动和访问能力的标准化,理解其功能边界,能助力正确选择容器和算法,避免因迭代器功能不足引发编译错误。

list的模拟实现(记得看注释):

接下来我将手把手教你们实现list(基础版)(要建自己的命名空间域哟!!!

第一步:

首先我们要明白list是一个双向链表,所以我们先要建立一个创建结点的类

template<class T>//模板对应着不同需求的数据
struct list_node
{list_node<T>* next;//指向下一个结点list_node<T>* prev;//指向上一个结点T _val; //存储数据//初始化(构造函数)list_node(const T& val = T())//记得给缺省值:next(nullptr), prev(nullptr), _val(val)
};

第二步:我们要实现list类:

template<class T>
class list
{
public:typedef list_node<T> Node;//简化名字
private:Node* _head;//哨兵位size_t _size;//计算list里面的数据个数};

第三步:完善我们的list类:

1.我们要初始化,可以写一个函数来初始化,再将它放入构造函数里面:

void empty_node()
{_head = new Node; //申请一个结点_head->next = _head;//因为只有一个哨兵位,双向链表里的方向指针,只能指向自身。_head->prev = _head;_size = 0;//记入数据多少
}
list()
{empty_node();
}

2.拷贝构造函数:要实现它,需对 list 进行插入、遍历等操作,但由此会产生一个问题:list 的这些功能能否和 vector 一样呢?答案显然是否定的。因为 vector 基于数组,是连续的内存空间;而 list 底层是双向链表,内存空间不连续。此时,迭代器就发挥作用了。这里用到的是双向迭代器,它能让我们更便捷地操作 list双向迭代器本质上是一个封装好的类,专门用于对链表的结点(即操作对象)进行各类操作。

  1.初始的迭代器:对于const修饰的数据无法处理(处理这个两种方式就是用模板,还有就是再写一个const版的迭代器)

//1.通常版
template<class T>
//template<class T, class Ref, class Ptr>
struct list_iterator
{typedef list_node<T> Node;//简化名称typedef list_iterator<T> self;//简化名称Node* _node;//创建一个结点,来链接迭代器与结点之间的联系list_iterator(Node* node)//为一些结点转化为迭代器类类型,好操作结点,实现我们好用的方式:_node(node){}//解引用的实现:1.避免拷贝 2.支持修改操作,在一些数据里不是指针或引用,就是临时的不会影响原数据。T& operator*(){return _node->_val;}//->访问形式的实现:->就是对指针的。T* operator->(){return &(_node->_val);}//下面的返回值,以及代码实现,是有一些小心思的:
//self& self 这是因为第一个前置无需担心原数据的修改,另一个是后置要担心原数据的修改,因为我们先要
//用到未++前的数据情况,而后再++。
//self tmp(*this)之前我们说过的迭代器初始化,在这里有体现,我们将原先的赋值拷贝给一个临时的,再++,返回的是临时的,这样就实现了后置。//前置++self& operator++(){_node = _node->next;return *this;}//后置++self operator++(int){self tmp(*this);_node = _node->next;return tmp;}//前置--self& operator--(){_node = _node->prev;return *this;}//后置--self operator--(int){self tmp(*this);_node = _node->prev;return tmp;}//比较:返回的是bool类型,这里传的是迭代器引用(防拷贝),并且用了const修饰,最后的 const 表明这个成员函数不会修改当前对象的状态。判断两个迭代器是否指向同一个节点bool operator!=(const self& x)const{return _node != x._node;}bool operator==(const self& x)const{return _node == x._node;}
};
//2.为了是应const类型的数据,我们可以用模板多个数据的定义。template<class T, class Ref, class Ptr>
struct list_iterator
{typedef list_node<T> Node;//简化名称typedef list_iterator<T,Ref,Ptr> self;//简化名称Node* _node;//创建一个结点,来链接迭代器与结点之间的联系list_iterator(Node* node)//为一些结点转化为迭代器类类型,好操作结点,实现我们好用的方式:_node(node){}//解引用的实现:1.避免拷贝 2.支持修改操作,在一些数据里不是指针或引用,就是临时的不会影响原数据。Ref operator*(){return _node->_val;}//->访问形式的实现:->就是对指针的。Ptr operator->(){return &(_node->_val);}//......上面的内容,没有改变};

2.迭代器的访问:
 

template<class T>
class list
{
public:typedef list_node<T> Node;//简化名字typedef list_iterator<T, T&, T*> iterator;//模板实例化typedef list_iterator<const T, const T&, const T*> const_iterator;//模板实例化
//iterator()这个是为了改为迭代器类类型好访问iterator begin(){return iterator(_head->next);}const_iterator begin()const{return const_iterator(_head->next);}iterator end(){return iterator(_head);}const_iterator end()const{return const_iterator(_head);}//................
}

3.拷贝构造函数的实现:


list(const list<T>& it)
{empty_node();//初始化for (auto& e : it)//一个个插入数据{push_back(e);//尾插}
}void push_back(const T& x)
{insert(end(), x);//用insert来实现尾插
}iterator insert(iterator pos, const T& x)//第一个参数迭代器类类型,用来访问。
{//申请前(prev)中(prev)以及新结点 三个结点 而插入就是再prev与cur中间。修改他们的前后指针指向。Node* cur = pos._node;Node* prev = cur->prev;Node* newnode = new Node(x);prev->next = newnode;cur->prev = newnode;newnode->next = cur;newnode->prev = prev;++_size;//计入增加大小return newnode;//返回值是迭代器,指向新建的结点。方便后续操作。以及避免迭代器失效的问题
}

第四步:

erase函数以及插入,删除函数和重载=和析构函数:

在链表的删除操作(erase)中,会导致迭代器失效,具体情况如下:

  • 被删除节点的迭代器失效原因:链表迭代器是对节点指针的封装,删除操作里,被删除节点会被delete释放内存,指向该节点的迭代器所关联的指针就成了野指针(指向已释放内存),野指针无法安全访问和使用,所以这个迭代器彻底失效。
  • 注意事项:删除操作后,被删除节点的迭代器绝对不能再使用(如解引用、递增等),否则会引发未定义行为(程序崩溃、数据错误等)。
  • erase函数的应对erase函数会返回被删除节点的下一个节点的迭代器,以此替代失效的迭代器,保障后续操作(如继续遍历)的安全性。
void swap(list<T>& it)//用库里面的swap函数进行交换,传的是list类的引用
{std::swap(_head, it._head);std::swap(_size, it._size);
}
//重载赋值就是将list的类里面的成员变量给赋值过去
list<T>& operator=(list<T> it)
{swap(it);return *this;
}
//销毁就是要前(prev)中(我们要删的)后(next)三个指针,我们销毁就是将原先指向cur的给改成prev和next之间的关系,返回的是下一个结点
iterator erase(iterator pos)
{assert(pos != end());Node* cur = pos._node;Node* prev = cur->prev;Node* next = cur->next;prev->next = next;next->prev = prev;delete cur;--_size;return next;
}void push_front(const T& x)
{insert(begin(), x);
}
//为什么要-- 这是因为尾删的数据在哨兵位的前面(end()返回的是哨兵位)
void pop_back()
{erase(--end());
}void pop_front()
{erase(begin());
}//通过迭代器的遍历来进行,由于erase的是返回下一个结点的,所以不需要像我们之前的++遍历下去
void clear()
{iterator it = begin();while (it != end()){it = erase(it);}_size = 0;
}~list()
{clear();delete _head;_head = nullptr;
}
//计算数据多少
size_t size()const
{return _size;
}

终于结束了!!!

list模拟完整代码:

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace xin
{template<class T>struct list_node{list_node<T>* next;list_node<T>* prev;T _val;list_node(const T& val = T())//记得给缺省值:next(nullptr), prev(nullptr), _val(val)};template<class T, class Ref, class Ptr>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T, Ref, Ptr> self;Node* _node;list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}Ptr operator->(){return &(_node->_val);}//前置++self& operator++(){_node = _node->next;return *this;}//后置++self operator++(int){self tmp(*this);_node = _node->next;return tmp;}//前置--self& operator--(){_node = _node->prev;return *this;}//后置--self operator--(int){self tmp(*this);_node = _node->prev;return tmp;}bool operator!=(const self& x)const{return _node != x._node;}bool operator==(const self& x)const{return _node == x._node;}};template<class T>class list{public:typedef list_node<T> Node;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<const T, const T&, const T*> const_iterator;iterator begin(){return iterator(_head->next);}const_iterator begin()const{return const_iterator(_head->next);}iterator end(){return iterator(_head);}const_iterator end()const{return const_iterator(_head);}void empty_node(){_head = new Node;_head->next = _head;_head->prev = _head;_size = 0;}list(){empty_node();}void swap(list<T>& it){std::swap(_head, it._head);std::swap(_size, it._size);}list<T>& operator=(list<T> it){swap(it);return *this;}list(const list<T>& it){empty_node();for (auto& e : it){push_back(e);}}void push_back(const T& x){insert(end(), x);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->prev;Node* newnode = new Node(x);prev->next = newnode;cur->prev = newnode;newnode->next = cur;newnode->prev = prev;++_size;return newnode;}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->prev;Node* next = cur->next;prev->next = next;next->prev = prev;delete cur;--_size;return next;}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}~list(){clear();delete _head;_head = nullptr;}size_t size()const{return _size;}private:Node* _head;size_t _size;};
}

list与vector的对比:

对比项vectorlist
底层结构动态顺序表,一段连续空间带头结点的双向循环链表
随机访问支持随机访问,访问某个元素效率 (O(1))不支持随机访问,访问某个元素效率 (O(N))
插入和删除任意位置插入和删除效率低,需搬移元素,时间复杂度 (O(N));插入可能扩容,效率更低任意位置插入和删除效率高,无需搬移元素,时间复杂度 (O(1))
空间利用率底层为连续空间,不易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点易造成内存碎片,空间利用率低,缓存利用率低
迭代器原生态指针对原生态指针(节点指针)进行封装
迭代器失效插入元素可能因扩容导致迭代器失效;删除时当前迭代器需重新赋值否则失效插入元素不会导致迭代器失效;删除元素时仅当前迭代器失效,其他不受影响
使用场景需要高效存储、支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

❤️总结

相信坚持下来的你一定有了满满的收获。那么也请老铁们多多支持一下,点点关注,收藏,点赞。❤️

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

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

相关文章

【Python】数据可视化之分布图

分布图主要用来展示某些现象或数据在地理空间、时间或其他维度上的分布情况。它可以清晰地反映出数据的空间位置、数量、密度等特征&#xff0c;帮助人们更好地理解数据的内在规律和相互关系。 目录 单变量分布 变量关系组图 双变量关系 核密度估计 山脊分布图 单变量分布…

DDD+WebAPI实战

DDD+WebAPI实战 DDD(领域驱动设计,Domain-Driven Design)是一种面向对象的设计方法,它强调将业务逻辑封装在模型中,并通过这些模型来驱动整个应用的设计。在.NET环境中,特别是在使用ASP.NET Core和Web API构建应用时,DDD可以帮助我们更好地组织代码,使得业务逻辑更加清…

人力资源管理的思维方法学习笔记1

北京师范大学政府管理学院1.课程介绍&#xff1a; 讲述视角上&#xff0c;本课程侧重人力资源管理的思维方式&#xff0c;即人力资源管理理论和时间的不同视角和主导范式的分析。这既是对人力资源管理理论发展的凝练&#xff0c;也是对人力资源管理实践演进过程的总结。对于把握…

适应新环境:Trae编辑器下的IDEA快捷键定制

介绍&#xff1a;学习如何在Trae编辑器中配置IntelliJ IDEA风格的快捷键&#xff0c;减少开发环境间的切换成本&#xff0c;提升编码效率。通过安装插件或手动调整&#xff0c;让你更快适应新工具大家好&#xff0c;我是凯哥Java本文标签&#xff1a;代码编辑效率、Trae快捷键、…

基于YOLO8的汽车碰撞事故检测系统【数据集+源码+文章】

基于YOLOv8和Streamlit的汽车碰撞事故检测系统 文末附下载地址 开发目的 随着城市化进程的加快和机动车保有量的持续攀升&#xff0c;道路交通安全问题日益突出&#xff0c;汽车碰撞事故频发不仅严重威胁驾乘人员的生命安全&#xff0c;也对公共秩序、应急响应效率及交通管理…

Unity FARO 测量臂:从零构建实时数字孪生系统

前言:当精准测量遇见实时渲染 在高端制造、质量检测和逆向工程领域,法奥 (FARO) 测量臂是精准的代名词。它能以亚毫米级的精度捕捉现实世界中的三维坐标。现在,想象一下,如果我们将这种精度与 Unity 的强大实时渲染能力结合起来,会发生什么? 我们将得到一个数字孪生 (D…

延迟 队列

概念 延迟队列顾名思义就是消息不立即发送给消费者消费&#xff0c;而是延迟一段时间再交给消费者。 RabbitMQ本身没有直接支持延迟队列的的功能&#xff0c;但是可以通过前面所介绍的TTL死信队列的方式组合 模拟出延迟队列的功能. RabbitMQ 有些版本还支持延迟队列的插件安…

Windows+Docker一键部署CozeStudio私有化,保姆级

在 ​Windows环境​ 下&#xff0c;通过docker&#xff0c;使用 ​火山引擎Doubao-Seed-1.6模型&#xff0c;面向 ​小白新手​ 的 ​Coze Studio私有化部署详细步骤。整个过程分为四大阶段&#xff0c;包含每一步的指令、成功标志。 Coze Studio 私有化部署指南&#xff08;W…

【HEMCO Reference Guide 参考指南第二期】配置文件的结构和语法

配置文件的结构和语法 HEMCO 配置文件的结构和语法(The HEMCO configuration file) 1. Settings(设置) 2. Extension Switches(扩展模块开关) 3. Base Emissions(基础排放配置) 4. Scale Factors(缩放因子) 5. Masks(掩膜区域) 6. Data Collections(数据集合) 参…

01.单例模式基类模块

一、单例模式的构成1、私有的静态成员变量2、公共的静态成员属性或方法3、私有构造函数using System.Collections; using System.Collections.Generic; using UnityEngine;public class BaseManager : MonoBehaviour {void Start(){}// Update is called once per framevoid Up…

[网络入侵AI检测] 深度前馈神经网络(DNN)模型

第4章&#xff1a;深度前馈神经网络&#xff08;DNN&#xff09;模型 欢迎回来&#x1f43b;‍❄️ 在第1章&#xff1a;分类任务配置&#xff08;二分类 vs. 多分类&#xff09;中&#xff0c;我们学习了如何配置模型以回答不同类型的问题&#xff1b;在第2章&#xff1a;数…

【目录-多选】鸿蒙HarmonyOS开发者基础

All look at the answer 针对包含文本元素的组件&#xff0c;例如Text、Button、TextInput等&#xff0c;可以使用下列哪些属性关于ForEach(arr, itemGenerator, index)组件的描述正确的是下面哪些容器组件是可以滚动的关于Tabs组件和TabContent组件&#xff0c;下列描述正确的…

第一讲 Vscode+Python+anaconda 安装

1、vscode下载和安装官网下载最新版&#xff1a;https://code.visualstudio.com/Download注&#xff1a;文件夹最好不要出现中文和空格 2、将vscode修改为中文环境注意&#xff1a;右下角弹出提示框&#xff0c;点击“yes”若不慎关闭了对话框&#xff0c;也不要紧&#xff0c;…

《sklearn机器学习——回归指标2》

均方对数误差&#xff08;mean_squared_log_error函数&#xff09; mean_squared_log_error函数计算与平方&#xff08;二次方&#xff09;对数误差或损失的期望值相一致的风险指标。 Mean Squared Logarithmic Error 参数与返回值 函数简介 mean_squared_log_error 是用于计算…

当电力设计遇上AI:良策金宝AI如何重构行业效率边界?

在工程设计行业&#xff0c;我们常说“经验为王”。一个资深工程师的价值&#xff0c;往往体现在他对规范的熟悉、对计算的把握、对图纸的掌控。但今天&#xff0c;这个“王座”正在被重新定义。不是经验不重要了&#xff0c;而是——效率的边界&#xff0c;正在被AI重构。以良…

【深度学习】重采样(Resampling)

在深度学习的背景下&#xff0c;重采样主要涉及两个方面&#xff1a; 数据层面的重采样&#xff1a;处理不平衡数据集。模型层面的重采样&#xff1a;在神经网络内部进行上采样&#xff08;UpSampling&#xff09;或下采样&#xff08;DownSampling&#xff09;&#xff0c;常见…

计算机实现乘法运算的方式---ChatGPT 5 thinking作答

计算机如何实现“乘法” 下面分层次把乘法在数据表示 → 整数硬件/软件 → 大整数 → 浮点数 → 特殊场景里的主流实现方式讲清楚&#xff0c;并给出取舍建议与简单伪代码。0&#xff09;前置&#xff1a;数的表示 无符号整数&#xff1a;按二进制位权求值。有符号整数&#xf…

Ubuntu 安装 / 配置 VNC

一、基础环境准备 1. 更新 sudo apt update 2. 安装 VNC 服务器 & 轻量桌面(XFCE) # 安装 TightVNC 服务器 + XFCE 桌面(推荐轻量方案) sudo apt install tightvncserver xfce4 xfce4-goodies xterm -y二、核心配置:让 VNC 加载桌面环境 1. 初始化 VNC 密码(首次…

计算机大数据毕业设计推荐:基于Spark的新能源汽车保有量可视化分析系统

精彩专栏推荐订阅&#xff1a;在下方主页&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、项目介绍二、…

Android Looper源码阅读

看下Android Looper源代码&#xff0c;有助于理解Android系统消息循环流程、handler机制。Looper注释为class used to run a message loop for a thread&#xff0c; 即用于为一个线程运行消息循环&#xff0c; 或者说循环处理一个线程的消息。 Looper源码先看下这个类里的变量…