list【2】模拟实现(含迭代器实现超详解哦)
模拟实现list
- 引言(实现概述)
- list迭代器实现
- 默认成员函数
- operator* 与 operator->
- operator++ 与 operator--
- operator== 与 operator!=
- 迭代器实现概览
- list主要接口实现
- 默认成员函数
- 构造函数
- 析构函数
- 赋值重载
- 迭代器
- 容量
- 元素访问
- 数据修改
- insert
- erase
- push_back 与 push_front
- pop_back 与 pop_front
- clear
- swap
- 源码概览
- 总结
引言(实现概述)
在前面,我们介绍了list的使用:
戳我看list的介绍与使用详解哦
在本篇文章中将重点介绍list的接口实现,通过模拟实现可以更深入的理解与使用list

我们模拟实现的 list 底层是一个带头双向循环链表
在实现list时,我们首先需要一个结构体以表示链表中结点的结构list_node,大致包括数据与指向前后结点的指针:
template<class T>
struct list_node //结点类
{list_node<T>* _prev;list_node<T>* _next;T _date;list_node(const T& date = T()) //匿名对象: _prev(nullptr), _next(nullptr), _date(date){}
};
在有了结点之后,还需要一个 list类,包括双向链表的头结点指针_pHead,链表中的元素个数_size:
template<class T>
class list //带头双向循环链表
{typedef list_node<T> Node;
private:Node* _pHead;size_t _size;
};
大致结构如下:

关于带头双向循环链表的实现可以参考之前的C语言版本实现,在本篇文章中结构将不是最重点的内容:戳我看C语言实现带头双向循环链表详解哦
与vector相同,list是一个类模板,其声明与定义不能分离。我们将模拟实现的list放在我们创建的命名空间内,以防止与库发生命名冲突。
在list的模拟实现中,我们只实现一些主要的接口,包括默认成员函数、迭代器、容量、元素访问与数据修改:
list迭代器实现
与vector不同,list的迭代器是指针的封装,通过运算符重载来实现原生指针的功能。
我们可以通过封装结点的指针,即list_node<T>*,来实现迭代器:
默认成员函数
对于默认成员函数,其实我们只需要实现构造函数即可,这个__list_iterator类的属性只有一个结构体指针,并不存在类中申请的资源,所以编译器生成的析构函数与赋值运算符重载就够用了,不需要再实现了。
- 默认构造
对于默认构造函数,我们可以使用缺省参数,即参数类型为结构体指针,缺省值为nullptr。
直接在初始化列表中用参数初始化类属性即可:
__list_iterator(Node* pNode = nullptr):_pNode(pNode){}
- 拷贝构造
对于拷贝构造,参数必须是类类型的引用,可以加上const修饰(我们可以在类中将类类型__list_iterator<T, Ref, Ptr>重命名为self,以方便书写)
在函数中直接赋值即可:
__list_iterator(const self& it){_pNode = it._pNode;}
operator* 与 operator->
迭代器使用时应该是与指针基本类似的,所以也需要重载*与->。
- 重载
*
指针当然可以进行解引用的操作,指向容器中元素的指针。对这个指针进行解引用操作结果就应该是该指针指向的元素。对于list的迭代器而言,解引用该迭代器的结果就应该是结点中的_data元素的引用,类型为&T:
(我们可以为模板参数加上一个参数,即Ref,它表示T&)
Ref operator*(){return _pNode->_date;}
- 重载
->
当T是自定义类型时,其指针还可以通过->直接访问到T类型对象_data中的元素,起指针作用的迭代器自然也需要实现这个功能。
但是对于这个运算符重载而言,它并不知道要返回T类型对象中的什么元素,所以这个operator->函数可以直接返回该迭代器对应的结点中的_data元素的指针,然后在调用的时候再通过->来访问其中元素:it->->a;(通过迭代器it访问T类型对象中的a元素)。
但是,这样的形式访问又与指针的用法不一致,所以这里有一个特殊的规定,即规定需要使用it->a;的方式通过迭代器访问T类型对象中的元素,以获得与原生指针相同的使用方式:
(我们可以为模板参数加上一个参数,即Ptr,它表示T*)
Ptr operator->(){return &(_pNode->_date);}
operator++ 与 operator–
- 重载
++
++操作即实现迭代器的指向向后移动一个元素,list的迭代器底层是一个结构体指针,所以只需要将当前_pNode->_next赋值给_pNode即可
且++分为前置++与后置++,在区别这两个的实现时,前面类和对象时已经详细介绍过了,即给后置++增加一个参数int,但是不传参,只用于区分前置与后置。
另外后置++需要创建临时对象,在*this++后必须要返回临时对象而非引用:
self& operator++(){_pNode = _pNode->_next;return *this;}self operator++(int){self temp(*this);_pNode = _pNode->_next;return temp;}
- 重载
--
重载--与前面的++类似,即将_pNode->_prev赋值给_pNode即可:
self& operator--(){_pNode = _pNode->_prev;return *this;}self operator--(int){self temp(*this);_pNode = _pNode->_prev;return temp;}
operator== 与 operator!=
对于==与!= 重载,即判断两个迭代器对象的属性是否相等即可:
bool operator==(const self& it){return _pNode == it._pNode;}bool operator!=(const self& it){return _pNode != it._pNode;}
迭代器实现概览
template<class T, class Ref, class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;Node* _pNode;__list_iterator(Node* pNode = nullptr):_pNode(pNode){}__list_iterator(const self& it){_pNode = it._pNode;}Ref operator*(){return _pNode->_date;}Ptr operator->(){return &(_pNode->_date);}self& operator++(){_pNode = _pNode->_next;return *this;}self operator++(int){self temp(*this);_pNode = _pNode->_next;return temp;}self& operator--(){_pNode = _pNode->_prev;return *this;}self operator--(int){self temp(*this);_pNode = _pNode->_prev;return temp;}bool operator==(const self& it){return _pNode == it._pNode;}bool operator!=(const self& it){return _pNode != it._pNode;}};
list主要接口实现
在实现list之前,我们可以对一些较为麻烦的类型进行重命名以方便书写:
typedef list_node<T> Node;
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
默认成员函数
构造函数
实现构造函数时,我们需要实现无参构造、n个指定元素构造、迭代器区间构造以及拷贝构造:
无参构造:
由于我们模拟实现的list底层为带头双向循环链表,所以在无参构造时虽然没有在list中放入元素,但是还使需要先放入一个空结点作为头节点。
创建头节点的操作在任何构造函数中都要先进行,所以我们将其封装为一个init_empty_list函数。这个初始化空list的函数需要new一个结点,然后使节点中的_prev与_next都指向它自身,最后将_size赋值为0:
void init_empty_list(){ _pHead = new Node();_pHead->_prev = _pHead;_pHead->_next = _pHead;_size = 0;}list(){init_empty_list();}
n个指定元素构造:
使用n个指定元素构造有两个参数,第一个就是int,第二个是const T&,缺省值为T()
函数中,首先调用init_empty_list构建一个头结点;
再循环,使用push_bake尾插n个指定元素value即可(push_back后面会实现):
list(int n, const T& value = T()){init_empty_list();while (n--){push_back(value);}}
迭代器区间构造:
是用迭代器区间构造函数是一个函数模板,可以使用任何容器的迭代器区间来构造list
函数中,首先调用init_empty_list构建一个头结点;
然后再循环,使用push_bake尾插first迭代器的解引用出的元素,当first与last相等时出循环:
template <class Iterator>list(Iterator first, Iterator last){init_empty_list();while (first != last){push_back(*first);++first;}}
拷贝构造:
拷贝构造函数的参数是一个const list<T>&
实现时,首先调用init_empty_list构建一个头结点;
然后范围for,使用push_bake将l中的元素逐一尾插到list中:
list(const list<T>& l){init_empty_list();for (auto el : l){push_back(el);}}
析构函数
析构函数需要实现释放list中的资源。
首先复用clear,清空list中的元素。clear中会实现释放结点中的资源,后面部分会实现;
再delete _pHead;,释放头节点中的资源,它会调用结点结构体的析构函数:
~list(){clear();delete _pHead;}
赋值重载
对于赋值运算符重载,我们直接使用新写法,即先使用参数l创建一个临时对象;
然后使用swap将临时对象与*this交换(后面会实现swap函数);
最后返回*this即可,创建的临时对象就会在函数栈帧销毁时自动释放:
list<T>& operator=(const list<T>& l) //list& operator=(const list l) 对于赋值重载,这样也可{list<T> temp(l);swap(temp);return *this;}
迭代器
在前面已经实现了list的迭代器,它是结点指针的封装;
这里暂时只实现begin与end,关于反向迭代器的实现在后面会详细介绍。
begin返回首元素的地址,即头结点的下一个结点的地址;
end返回尾元素下一个位置的地址,即头节点的地址,他们分别重载有const版本:
iterator begin(){return iterator(_pHead->_next);}iterator end(){return iterator(_pHead);}const_iterator begin() const{return const_iterator(_pHead->_next);}const_iterator end() const{return const_iterator(_pHead);}
容量
在容器部分,由于list并没有容量的概念,所以我们只需要实现size与empty即可;

我们在list的属性中,我们设置了_size,在插入元素时_size++,删除元素时_size--,所以这里只需要返回_size的值即可;
当_size == 0时,list为空,empty返回true,否者返回false:
size_t size() const{return _size;}bool empty() const{if (_size == 0)return true;elsereturn false;}
元素访问
由于list在任意位置访问元素的成本较高,就没有提供operator[]的接口,所以我们只需要实现front与back即可。分别返回首尾的元素,有普通对象与const对象两个重载版本:

在实现时,我们可以借助list的属性_pHead,即头结点的指针来访问首尾元素:
我们模拟实现list的底层是带头双向循环链表,所以list中的第一个元素就是_pHead->_next指向的结点中的元素;list中的_pHead->_prev指向的结点中的元素:
front只需要返回 _pHead->_next->_date 即可;
back返回_pHead->_prev->_date即可,返回值类型为T&,const版本就返回const T&即可:
T& front(){return _pHead->_next->_date;}const T& front()const{return _pHead->_next->_date;}T& back(){return _pHead->_prev->_date;}const T& back()const{return _pHead->_prev->_date;}
数据修改

insert
list 的结构使在任意位置插入数据的效率是较高的,只需要创建结点,再链接到pos位置前即可:
在实现insert时,首先new一个结点,类型为Node,并用val初始化(这个Node类型是前面重命名后的类型);
这时我们需要记录pos位置的结点指针为cur,pos位置前面的结点指针为prev,以方便后续链接;
然后将pos结点的前一个结点与新结点链接,即newnode与prev链接;
再将pos结点与新结点链接,即newnode与cur链接;
最后,更新_size,并返回新结点的迭代器:
// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* newnode = new Node(val);Node* cur = pos._pNode;Node* prev = cur->_prev;newnode->_prev = prev;prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;++_size;return iterator(newnode);}
erase
erase实现时,只需要释放pos位置的结点,并链接剩余的结点即可:
首先assert判断list是否为空;
这时我们需要记录pos位置的结点指针为cur,pos位置前面的结点指针为prev,pos的后一个结点指针为next,以方便后续链接;
然后直接链接pos位置的前一个结点与后一个结点,即链接prev与next即可;
最后,释放cur指向的结点,更新_size,并返回next:
// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(!empty());Node* cur = pos._pNode;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return iterator(next);}
push_back 与 push_front
对于头插与尾插的实现,复用insert即可:
push_front,即在首结点的前面一个位置插入一个元素,即在begin()迭代器位置插入;
push_back,即在尾结点的后一个位置插入一个元素,即在end()位置插入:
void push_back(const T& val){insert(end(), val);}void push_front(const T& val){insert(begin(), val);}
pop_back 与 pop_front
对于头删尾删的实现,复用erase即可:
pop_front,即删除头节点,即 erase删除begin()位置的结点 即可;
pop_back,删除尾结点,即 erase删除end()前面一个结点即可,但是由于list迭代器不支持-操作,所以这里传参为--end():
void pop_front(){erase(begin());}void pop_back(){erase(--end());}
clear
clear用于清理list中的所有元素,可以直接复用erase来实现清理:
我们可以通过遍历迭代器的方式逐一释放结点:
令it的初始值为begin(),循环逐一erase删除,当it等于end()的时候终止循环,就可以实现删除所有结点并保留头节点;
另外,由于erase删除某节点后,会返回删除节点的下一个位置,所以只要把返回值载赋值给it就实现了迭代器的向后移动:
void clear(){iterator it = begin();while (it != end()){it = erase(it);//erase返回删除的结点的下一个位置的迭代器}}
swap
实现list的交换函数时,只需要使用库swap交换list的属性即可,即交换_pHead与_size:
void swap(list<T>& l){std::swap(_pHead, l._pHead);std::swap(_size, l._size);}
源码概览
(关于反向迭代器的实现在后面会详细介绍,现在可以暂时忽略)
#include<iostream>
#include<cassert>
#include"my_reverse_iterator.h"namespace qqq
{template<class T>struct list_node{list_node<T>* _prev;list_node<T>* _next;T _date;list_node(const T& date = T()) //匿名对象: _prev(nullptr), _next(nullptr), _date(date){}};template<class T, class Ref, class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;Node* _pNode;__list_iterator(Node* pNode = nullptr):_pNode(pNode){}__list_iterator(const self& it){_pNode = it._pNode;}Ref operator*(){return _pNode->_date;}Ptr operator->(){return &(_pNode->_date);}self& operator++(){_pNode = _pNode->_next;return *this;}self operator++(int){self temp(*this);_pNode = _pNode->_next;return temp;}self& operator--(){_pNode = _pNode->_prev;return *this;}self operator--(int){self temp(*this);_pNode = _pNode->_prev;return temp;}bool operator==(const self& it){return _pNode == it._pNode;}bool operator!=(const self& it){return _pNode != it._pNode;}};template<class T>class list //带头双向循环链表{typedef list_node<T> Node;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;public:/ constructor and destructor void init_empty_list(){ _pHead = new Node();_pHead->_prev = _pHead;_pHead->_next = _pHead;_size = 0;}list(){init_empty_list();}list(int n, const T& value = T()){init_empty_list();while (n--){push_back(value);}}template <class Iterator>list(Iterator first, Iterator last){init_empty_list();while (first != last){push_back(*first);++first;}}list(const list<T>& l){init_empty_list();for (auto el : l){push_back(el);}}list<T>& operator=(const list<T>& l) //list& operator=(const list l) 对于赋值重载,这样也可{list<T> temp(l);swap(temp);return *this;}~list(){clear();delete _pHead;}// List Iterator///iterator begin(){return iterator(_pHead->_next);}iterator end(){return iterator(_pHead);}const_iterator begin() const{return const_iterator(_pHead->_next);}const_iterator end() const{return const_iterator(_pHead);}reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}/List Capacity//size_t size() const{return _size;}bool empty() const{if (_size == 0)return true;elsereturn false;}///List Access///T& front(){return _pHead->_next->_date;}const T& front()const{return _pHead->_next->_date;}T& back(){return _pHead->_prev->_date;}const T& back()const{return _pHead->_prev->_date;}List Modify//void push_back(const T& val){insert(end(), val);}void pop_back(){erase(--end());}void push_front(const T& val){insert(begin(), val);}void pop_front(){erase(begin());}// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* newnode = new Node(val);Node* cur = pos._pNode;Node* prev = cur->_prev;newnode->_prev = prev;prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;++_size;return iterator(newnode);}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(!empty());Node* cur = pos._pNode;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return iterator(next);}void clear(){iterator it = begin();while (it != end()){it = erase(it);//erase返回删除的结点的下一个位置的迭代器}}void swap(list<T>& l){std::swap(_pHead, l._pHead);std::swap(_size, l._size);}private:Node* _pHead;size_t _size;};
};
总结
到此,关于list的模拟实现就到此结束了
模拟实现容器并不是为了造一个更好的轮子,而是为了更好的理解与使用容器
如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出
如果本文对你有帮助,希望一键三连哦
希望与大家共同进步哦
相关文章:
list【2】模拟实现(含迭代器实现超详解哦)
模拟实现list 引言(实现概述)list迭代器实现默认成员函数operator* 与 operator->operator 与 operator--operator 与 operator!迭代器实现概览 list主要接口实现默认成员函数构造函数析构函数赋值重载 迭代器容量元素访问数据修改inserterasepush_ba…...
Nginx+Tomcat的动静分离与负载均衡
目录 前言 一、案例 二、Nginx的高级用法 三、tomcat部署 四、Nginx部署 五、测试 总结 前言 通常情况下,一个 Tomcat 站点由于可能出现单点故障及无法应付过多客户复杂多样的请求等情况,不能单独应用于生产环境下,所以我们需要一套更…...
【设计模式】Head First 设计模式——策略模式 C++实现
设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 设计思想 将行为想象为一族算法,定义算法族…...
c#object类中方法的使用
C#中的Object类是所有类的基类,它定义了一些通用的方法和属性,可以在任何对象上使用。以下是Object类中常用的方法和属性的使用: 1.ToString():将对象转换为字符串表示形式。 string str obj.ToString();2.Equals():…...
三种常用盒子布局的方法
在Vue中,可以使用各种CSS布局属性和技巧来设置盒子的布局。以下是一些常用的方法: 1.使用Flexbox布局:在包含盒子的父元素上设置display: flex,然后可以使用flex-direction、justify-content和align-items 等属性来控制盒子的布局…...
GB28181学习(二)——注册与注销
概念 使用REGISTER方法进行注册和注销;注册和注销应进行认证,认证方式应支持数字摘要认证方式,高安全级别的宜支持数字证书认证;注册成后,SIP代理在注册过期时间到来之前,应向注册服务器进行刷新注册&…...
【Linux】线程安全-信号量
文章目录 信号量原理信号量保证同步和互斥的原理探究信号量相关函数初始化信号量函数等待信号量函数释放信号量函数销毁信号量函数 信号量实现生产者消费者模型 信号量原理 信号量的原理:资源计数器 PCB等待队列 函数接口 资源计数器:对共享资源的计…...
数字IC验证——PSS可移植测试用例
PSS是Accellera组织定义的测试用例生成规范,其思想是定义一个抽象模型,EDA工具可以从中生成适用于每个设计层次结构和每个验证平台的测试,即PSS定义了统一的测试场景,而场景的使用可以横跨不同验证层次和配置。 这种特性决定了PSS…...
java设计模式---策略模式
策略模式的定义 策略设计模式是一种行为设计模式。当在处理一个业务时,有多种处理方式,并且需要再运行时决定使哪一种具体实现时,就会使用策略模式。 策略模式的类图: 策略模式的实现 在支付业务中,有三种付款方式&…...
5-redis集群搭建安装
1.先决条件 1.1.OS基础配置 CentOS为了能够正常安装redis,需要对CentOS进行常规的一些基础配置,主要有:关闭防火墙与selinux,设置主机名,配置虚拟机IP地址使其能够与外网ping通,配置IP地址与主机名映射,配置yum源。具体配置参见: Linux常规基础配置_小黑要上天的博客…...
(数字图像处理MATLAB+Python)第十一章图像描述与分析-第七、八节:纹理描述和其他描述
文章目录 一:纹理描述(1)联合概率矩阵法A:定义B:基于联合概率矩阵的特征C:程序 (2)灰度差分统计法A:定义B:描述图像特征的参数 (3)行程…...
MySQL提权
参考: mysql提权篇 | Wh0ales Blog MySQL 提权方法整理 - Geekbys Blog MySQL_UDF提权漏洞复现-云社区-华为云 MYSQL UDF手动提权及自动化工具使用_udf提权工具_小直789的博客-CSDN博客 MySQL提权的三种方法 - FreeBuf网络安全行业门户 ......
FPGA优质开源项目 – UDP万兆光纤以太网通信
本文开源一个FPGA项目:UDP万兆光通信。该项目实现了万兆光纤以太网数据回环传输功能。Vivado工程代码结构和之前开源的《UDP RGMII千兆以太网》类似,只不过万兆以太网是调用了Xilinx的10G Ethernet Subsystem IP核实现。 下面围绕该IP核的使用、用户接口…...
如何中mac上安装多版本python并配置PATH
摘要 mac 默认安装的python是 python3,但是如果我们需要其他python版本时,该怎么办呢? 例如:需要python2 版本,如果使用homebrew安装会提示没有python2。同时使用python --version 会发现commond not found。 所以本…...
window 常用基础命令
0、起步 0-1) 获取命令的参数指引 netstat /? 0-2) 关于两个斜杠: window 文件路径中使用反斜杠:\ linux 文件路径中使用:/ 1、开关机类指令 shutdown /s # 关机shutdown /r # 重启shutdown /l …...
lintcode 1815 · 警报器 【simple vip 前缀和数组】
题目 https://www.lintcode.com/problem/1815 一个烟雾警报器会监测len秒内的烟雾值,如果这段时间烟雾值平均值大于k那么警报器会报警。现在给你n个数代表刚开始工作n秒内警报器监测的烟雾值(警报器从第len秒开始判断是否报警),…...
【强化学习】MDP马尔科夫链
基本元素 状态集:表示智能体所处所有状态的全部可能性的集合。类似的集合,行为集,回报集决策:规定我在某个状态下,我做出某个action马尔可夫链:学术上来说是无记忆性质。说白了就是我只在乎我目前的状态。…...
SpringBoot自写项目记录
设置静态资源映射 Slf4j 用来打印日志 Configuration Slf4j //设置静态资源映射 public class WebMvcConfig extends WebMvcConfigurationSupport {Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("开始静态资源配置");r…...
Windows10上使用llama-recipes(LoRA)来对llama-2-7b做fine-tune
刚刚在Windows10上搭建环境来对llama2做finetune,里面坑还是挺多的,这里把印象中的坑整理了一下以作备忘。 llama-recipes是meta的开源项目,Github地址为:GitHub - facebookresearch/llama-recipes: Examples and recipes for Ll…...
06-限流策略有哪些,滑动窗口算法和令牌桶区别,使用场景?【Java面试题总结】
限流策略有哪些,滑动窗口算法和令牌桶区别,使用场景? 常见的限流算法有固定窗口、滑动窗口、漏桶、令牌桶等。 6.1 固定窗口 概念:固定窗口(又称计算器限流),对一段固定时间窗口内的请求进行…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
