【C++心愿便利店】No.14---C++之探索list底层原理
文章目录
- 前言
- 一、list的介绍及使用
- 1.1 list的介绍
- 1.2 list的使用
- 1.2.1 list的构造
- 1.2.2 list iterator的使用
- 1.2.3 list capacity
- 1.2.4 list element access
- 1.2.5 list modifiers
- 1.2.6 list operations
- 1.2.7 list的迭代器失效
- 二、list的模拟实现
- 2.1 定义一个结构体实现list的节点
- 2.2 list的成员变量
- 2.3 list迭代器的封装实现
- 2.3.1 普通迭代器
- 2.3.2 const迭代器
- 2.4 list成员函数
- 2.4.1 构造函数
- 2.4.2 拷贝构造函数
- 2.4.3 赋值运算符重载
- 2.4.4 迭代器相关
- 2.4.5 insert
- 2.4.6 erase
- 2.4.7 push_back()
- 2.4.8 push_front()
- 2.4.9 pop_back()
- 2.4.10 pop_front()
- 2.4.11 size()
- 2.4.12 clear()
- 2.4.13 析构函数
- 三、list与vector的对比
前言

👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:C++ 心愿便利店
🔑本章内容:list
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~
提示:以下是本篇文章正文内容,下面案例可供参考
一、list的介绍及使用
list的文档介绍
1.1 list的介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)
1.2 list的使用
list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展
的能力。以下为list中一些常见的重要接口
1.2.1 list的构造
| 构造函数( (constructor)) | 接口说明 |
|---|---|
| list() | 构造空的list |
| list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的元素 |
| list (InputIterator first, InputIterator last) | 用[first, last)区间中的元素构造list |
| list (const list& x) | 拷贝构造函数 |
void test_list1()
{list<int> l1;//构造空的listlist<int>l2(6, 6);//构造的list中包含n个值为val的元素list<int>l3(l2.begin(), l2.end());//用[first, last)区间中的元素构造listlist<int>l4(l3);//拷贝构造函数list<int>::iterator it = l2.begin();while (it != l2.end()){cout << *it << " ";it++;}cout << endl;for (auto e : l3){cout << e << " ";}cout << endl;for (auto e : l4){cout << e << " ";}cout << endl;
}
1.2.2 list iterator的使用
此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
| 函数声明 | 接口说明 |
|---|---|
| begin + end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
| rbegin + rend | 返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的reverse_iterator,即begin位置 |
void test_list2()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);// 使用正向迭代器遍历打印lt中的元素// list<int>::iterator it = l.begin(); //两种写法都对auto it = lt.begin(); while (it != lt.end()){cout << *it << " ";++it;}cout << endl;// 使用反向迭代器遍历打印lt中的元素// list<int>::reverse_iterator rit = l.rbegin();auto rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";++rit;}cout << endl;
}
【注意】
- begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
- rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
- 遍历链表只能使用迭代器和范围 for。
1.2.3 list capacity
| 函数声明 | 接口说明 |
|---|---|
| empty | 检测list是否为空,是返回true,否则返回false |
| size | 返回list中有效节点的个数 |
1.2.4 list element access
| 函数声明 | 接口说明 |
|---|---|
| front | 返回list的第一个节点中值的引用 |
| back | 返回list的最后一个节点中值的引用 |
1.2.5 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中的有效元素 |
1.2.6 list operations
| 函数声明 | 接口说明 |
|---|---|
| splice | 实现list拼接的功能,将源list的内容部分或全部元素删除,拼插入到目的list。 |
| remove | 删除特定值节点 |
| unique | 对链表中的元素去重,要求必须有序 |
| merge | 对两个有序的链表进行归并,得到一个有序的链表 |
| sort | 对链表中的元素进行排序 |
| reverse | 逆置 |
注意:链表排序只能使用 list 自身的 sort() 接口(其底层是利用归并排序原理),不能使用算法库的 sort,因为算法库中的 sort 底层是通过快排来实现的,快排涉及到三数取中,需要迭代器 - 迭代器,链表不能很好的支持。
void test_list3()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);for (auto e : lt){cout << e << " ";}cout << endl;lt.reverse();链表逆置可以使用 list 自身的接口,也可以使用算法库中的 reversefor (auto e : lt){cout << e << " ";}cout << endl;//sort(lt.begin(), lt.end());lt.sort();//默认升序< less//降序> greater//greater<int> gt;lt.sort(gt);lt.sort(greater<int>());//上面的两种写法都可以for (auto e : lt){cout << e << " ";}cout << endl;
}
————————————————————————————————————————————————————————————————————————————————
unique --- 去重(一定要记得有序)
void test_list4()
{list<int> lt;lt.push_back(1);lt.push_back(3);lt.push_back(2);lt.push_back(3);lt.push_back(3);lt.push_back(2);lt.push_back(5);lt.push_back(5);for (auto e : lt){cout << e << " ";}cout << endl;lt.unique();for (auto e : lt){cout << e << " ";}cout << endl;
}

虽然链表提供了排序接口,但是用链表对数据排序意义不大(当数据比较大时),效率太低了,更希望用 vector 来对数据进行排序 — 如下(具体可以通过对两者进行效率比对),但是数据较小时sort还是很有用的
//将li中的数据拷贝到vector
vector<int> v(lt.begin(),lt.end());
for (auto e : v)
{cout << e << " ";
}
cout << endl;
//排序
sort(v.begin(), v.end());
for (auto e : v)
{cout << e << " ";
}
cout << endl;
//拷贝回lt
lt.assign(v.begin(), v.end());
for (auto e : lt)
{cout << e << " ";
}
cout << endl;——————————————————————————————————————————————————————————————————————————————————————————
//对两者进行效率比对
void TestSort()
{srand(time(0));const int N = 5000000;vector<int> v;list<int> lt;v.reserve(N);//提前开好空间for (int i = 0; i < N; i++){auto e = rand();v.push_back(e);lt.push_back(e);}比较vector 和 list 的排序int begin1 = clock();sort(v.begin(), v.end());int end1 = clock();int begin2 = clock();lt.sort();int end2 = clock();printf("vector sort:%d\n", end1 - begin1);printf("list sort:%d\n", end2 - begin2);
}
迭代器的这种分类方式,是由容器的底层结构来决定的
| 迭代器类型(性质上分类) | 功能 及 示例 |
|---|---|
| 单向(InputIterator) | 支持 ++ (单链表、哈希表) |
| 双向(BidirectionalItreator) | 支持 ++/- - (双向链表、红黑树(map和set)) |
| 随机(RandomAccessIterator) | 支持 ++ / - - / + / - (vector、string、deque) |
可以看到算法库里面的sort:迭代器类型是随机(RandomAccessIterator)类型的所以不可以用算法库中的sort,以list中的reverse为例:迭代器是双向(BidirectionalItreator)类型的。

1.2.7 list的迭代器失效
list中insert 插入元素并不会导致迭代器失效, vector 中的 insert插入元素导致迭代器失效是因为,vector 中的 insert 会去扩容挪动数据,而 list 中的 insert 不会进行扩容挪动数据
前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响
void TestListIterator1()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array+sizeof(array)/sizeof(array[0]));auto it = l.begin();while (it != l.end()){//erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值l.erase(it); ++it;}
}
——————————————————————————————————————————————————————————————————————————————
// 改正
void TestListIterator()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> l(array, array+sizeof(array)/sizeof(array[0]));auto it = l.begin();while (it != l.end()){l.erase(it++); // it = l.erase(it);}
}
二、list的模拟实现
2.1 定义一个结构体实现list的节点
template<class T>
struct list_node//struct默认是公有的不受访问限定符限制
{T _data;list_node<T>*_next;list_node<T>*_prev;list_node(const T& x=T())//拷贝构造:_data(x),_next(nullptr),_prev(nullptr){}
};
2.2 list的成员变量
template<class T>
class list
{typedef list_node<T> Node;
public:private:Node* _head;
};
2.3 list迭代器的封装实现
list 的迭代器不再使用原生指针因为:
- 首先如果list 的迭代器使用原生指针,那对迭代器解引用得到的是一个节点,但是我们是希望对迭代器解引用可以得到节点里面存储的元素数据
- 其次 list 在底层的物理空间并不连续,如果使用原生指针作为 list 的迭代器,那对迭代器执行 ++ 操作,并不会让迭代器指向下一个节点。
所以需要对 list 的迭代器进行封装并对一些运算符进行重载以实现迭代器的效果。
2.3.1 普通迭代器
//迭代器的封装和运算符重载
template<class T>
struct __list_iterator
{typedef list_node<T>Node;typedef __list_iterator<T> self;Node* _node;__list_iterator(Node* node)//构造:_node(node){}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;}T& operator*()//因为要修改数据所以返回数据的&{return _node->_data;}bool operator==(const self& s){return _node == s._node;}bool operator!=(const self& s){return _node !=s._node ;}
};
迭代器不需要实现析构函数、拷贝构造函数、赋值运算符重载函数,直接使用默认生成的就可以(所以浅拷贝就足够了不需要深拷贝)
2.3.2 const迭代器
上述实现了普通迭代器,那 const 迭代器该怎样实现呢?
所谓const 迭代器本质:是限制迭代器指向的内容不能修改,而 const 迭代器自身可以修改,它可以指向其他节点。
const iterator这种写法,const 限制的就是迭代器本身,会让迭代器无法实现 ++ 等操作(所以const迭代器不是对普通迭代器+const修饰)。
为了实现const迭代器有两种方式:
- 单独写一个 _list_const_iterator 的类
template<class T>
struct __list_const_iterator
{typedef list_node<T>Node;typedef __list_const_iterator<T> self;Node* _node;__list_const_iterator(Node* node):_node(node){}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;}const T& operator*(){return _node->_data;}const T* operator->(){return &_node->_data;}bool operator==(const self& s){return _node == s._node;}bool operator!=(const self& s){return _node != s._node;}
};
- 在普通迭代器的基础上,再传递一个模板参数,让编译器来生成
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){}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;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const self& s) {return _node == s._node;}bool operator!=(const self& s){return _node != s._node;}
};
2.4 list成员函数
2.4.1 构造函数
list 本质上是一个带头双向循环链表。
void empty_init()
{_head = new Node;//这里需要传个值所以在拷贝构造的地方给个匿名对象_head->_next = _head;_head->_prev = _head;
}
list()
{empty_init();
}
2.4.2 拷贝构造函数
list(const list<T>& lt)//--->lt是一个const类型的
{empty_init();for (auto e : lt){push_back(e);}
}
2.4.3 赋值运算符重载
//两种写法:
list<int>& operator=(const list<int>& lt)
{if(this!=<){clear();//释放lt3;--->不清哨兵位的头结点可以继续插入for (auto e : lt)//遍历lt1{push_back(e);//把lt1中的数据插入到lt3}}return *this;
}
____________________________________________________________________________________
void swap(list<T>& lt)
{std::swap(_head,lt._head);//交换头指针std::swap(_size, lt._size);
}
list<int>& operator=(list<int>& lt)
{swap(lt);return *this;
}
2.4.4 迭代器相关
//普通迭代器:
iterator begin()
{return _head->_next;
}
iterator end()
{return _head;
}
//const迭代器:
const_iterator begin()const
{return _head->_next;
}
const_iterator end()const
{return _head;
}
2.4.5 insert
iterator insert(iterator pos, const T& val)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(val);prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;return iterator(newnode);
}
2.4.6 erase
iterator erase(iterator pos)
{Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;cur = nullptr;prev->_next = next;next->_prev = prev;_size--;return iterator(next);//返回pos的下一个位置
}
2.4.7 push_back()
void push_back(const T& x)
{
//找尾Node* tail = _head->_prev;
//插入节点 Node* newnode = new Node(x);tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;
}
————————————————————————————————————————————————————————————————————————————————
//直接复用insert
void push_back(const T& x)
{insert(end(),x);
}
2.4.8 push_front()
void push_front(const T& x)
{insert(begin(), x);
}
2.4.9 pop_back()
void pop_back(const T& x)
{erase(--end());
}
2.4.10 pop_front()
void pop_front(const T& x)
{erase(begin());
}
2.4.11 size()
size_t size()
{return _size;
}
2.4.12 clear()
void clear()
{iterator it = begin();while (it != end()){it = erase(it);//返回下一个位置的迭代器}
}
2.4.13 析构函数
~list()
{clear();delete _head;_head = nullptr;
}
三、list与vector的对比

相关文章:
【C++心愿便利店】No.14---C++之探索list底层原理
文章目录 前言一、list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list operations1.2.7 list的迭代器失效 二、list的模拟实现2.1 定义一个结构体实现list的…...
【广州华锐互动】VR防溺水安全内容体验提高群众防溺水意识
在全球各地,溺水是导致儿童和青少年死亡的主要原因之一。据世界卫生组织的统计,全球每年有超过36万人因溺水而死亡,其中大部分是儿童和青少年。因此,提供有效的防溺水教育和培训至关重要。随着科技的发展,虚拟现实&…...
【Skynet 入门实战练习】游戏模块划分 | 基础功能模块 | timer 定时器模块 | logger 日志服务模块
文章目录 游戏模块基础功能模块定时器模块日志模块通用模块 游戏模块 游戏从逻辑方面可以分为下面几个模块: 注册和登录网络协议数据库玩法逻辑其他通用模块 除了逻辑划分,还有几个重要的工具类模块: Excel 配置导表工具GM 指令测试机器人…...
python内置模块binascii,二进制数据和ASCII字符串之间进行转换
一、简介 binascii是Python标准库中的一个模块,提供了在二进制数据和ASCII字符串之间进行转换的功能。它包含了一些用于处理二进制数据的函数,可以进行二进制数据的编码、解码和转换。 二、方法 binascii.unhexlify(hexstr):将十六进制表示…...
如何开启MySQL的慢查询日志
说明:如果需要查看某一条SQL查询速度慢,并对慢的SQL进行优化,那么开启MySQL慢查询日志是一定要做的事情,本文介绍如何开启MySQL的慢查询日志; 查看MySQL慢查询是否开启 首先,输入下面的命令,查…...
Spine的BoundingBoxAttachment碰撞检测
引擎版本 —— cocos creator 2.3.4 游戏代码: //优先初始化的时候,获取到cc.PhysicsPolygonColliderthis._poly this.dragonFooAni.node.getComponent(cc.PhysicsPolygonCollider);//下面的修改顶点位置的方法可以在update里面去执行//获取骨骼动画上…...
Proteus下仿真AT89C51报“串行口通信失败,请检查电平适配是否正确。”解决办法
在Proteus下进行AT89C51串行口仿真时,如果遇到“串行口通信失败,请检查电平适配是否正确”的错误提示,以下是一些解决办法: 1. 了解AT89C51和外部设备的电平要求: 首先,了解AT89C51和外部设备之间的电平…...
微信小程序制作
如果你也想搭建一个小程序,但不知道如何入手,那么今天我就教你如何使用第三方制作平台,在短短三十分钟内搭建一个小程序。 一、登录小程序制作平台 首先,登录到小程序制作平台的官方网站或应用程序,进入后台管理系统。…...
快速在WIN11中本地部署chatGLM3
具体请看智谱仓库github:GitHub - THUDM/ChatGLM3: ChatGLM3 series: Open Bilingual Chat LLMs | 开源双语对话语言模型 或者Huggingface:https://huggingface.co/THUDM/chatglm3-6b 1. 利用Anaconda建立一个虚拟环境: conda create -n chatglm3 pyt…...
土地利用数据技术服务
一、背景介绍 土地是人类赖以生存与发展的重要资源和物质保障,在“人口-资源-环境-发展(PRED)”复合系统 中,土地资源处于基础地位。随着现代社会人口的不断增长以及工业化、城市化进程的加速&a…...
qml动画过渡Transition
文章目录 基本概念使用 `Transition`示例动画过渡高级用法示例:复杂动画过渡解释进阶用法在 QML 中,Transition 元素用于定义状态之间过渡时的动画。这是 QML 强大的状态机制的一部分,允许开发者创建平滑且吸引人的用户界面交互。使用 Transition,您可以定义当元素从一个状…...
Django(九、cookie与session)
文章目录 一、cookie与session的介绍HTTP四大特性 cookiesession Django操作cookie三板斧基于cookie的登录功能set_cookie 设置cookie 清空cookie设置cookie参数Django操作session设置session获取session清空sessionsession相关的参数设置过期时间 CBV添加装饰器 一、cookie与s…...
web前端之若依框架图标对照表、node获取文件夹中的文件名,并通过数组返回文件名、在html文件中引入.svg文件、require、icon
MENU 前言效果图htmlJavaScripstylenode获取文件夹中的文件名 前言 需要把若依原有的icon的svg文件拿到哦! 注意看生成svg的路径。 效果图 html <div id"idSvg" class"svg_box"></div>JavaScrip let listSvg [404, bug, build, …...
使用 goland 开发 golang 项目环境配置
方式1:使用 GOPATH 和 GOROOT 在 goland 中打开:Settings - Go,会看到 GOROOT、GOPATH,其相关解释与配置如下: GOROOT:对应 go 的安装路径,例如:D:\go\binGOPATH:是我们…...
Linux宝塔面板搭建Discuz论坛, 并内网穿透实现公网访问
Linux宝塔面板搭建Discuz论坛, 并内网穿透实现公网访问 文章目录 Linux宝塔面板搭建Discuz论坛, 并内网穿透实现公网访问前言1.安装基础环境2.一键部署Discuz3.安装cpolar工具4.配置域名访问Discuz5.固定域名公网地址6.配置Discuz论坛 📷 江池…...
[git] 忽略已经提交的文件或文件夹
文件已经被Git跟踪 如果某个文件已经被Git跟踪过(即已经添加到版本控制中),.gitignore文件对该文件将不起作用。您需要使用以下命令将该文件从Git中移除: git rm --cached <文件> 支持文件夹 -r <文件夹>...
大模型增量预训练参数说明
在增量预训练过程中通常需要设置三类或四类参数,模型参数,数据参数,训练参数,额外参数。 下面分别针对这四种参数进行说明。 欢迎关注公众号 模型参数 model_type模型类型,例如bloom,llama,baichuan,qwen等。 model_name_or_path模型名称或者路径。 tokenizer_name_or…...
成为AI产品经理——模型评估概述
目录 一、模型宣讲和评估的原因 二、模型宣讲 三、模型评估 1. 重要特征 ① 特征来源 ②特征意义 2.选择测试样本 3.模型性能和稳定性 一、模型宣讲和评估的原因 刘海丰老师提到他们在做一个金融AI产品未注重模型指标,过于注重业务指标,导致产生…...
内存屏障与JVM指令
内存屏障是一种同步原语,用于确保在并发程序中,当一个线程对内存中的数据进行修改后,其他线程可以及时地获取到最新的数据。 内存屏障可以确保指令的执行具有原子性、可见性和顺序性。在JVM中,内存屏障通常通过插入一段特殊的指令…...
深入理解JVM 类加载机制
深入理解JVM 类加载机制 虚拟机如何加载Class文件? Class文件中的信息进入到虚拟机后会发生什么变化? 类加载机制就是Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
