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

list的使用和模拟实现

目录

1.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

2.为什么使用迭代器?

3.list的模拟实现

3.1完整代码

3.2代码解析

4.list与vector的对比


1.list的介绍及使用

1.1 list的介绍

1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

1.2 list的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口

1.2.1 list的构造

构造函数

接口说明

list (size_type n, const value_type& val = value_type())

构造的list中包含n个值为val的元素

list ()

构造空的list

list (const list& x)

拷贝构造函数

list (InputIterator first, InputIterator last)

用两个迭代器[firs, last)区间中的元素构造list

1.2.2 list iterator的使用

此处,可暂时将迭代器理解成一个指针,该指针指向list中的某个节点

函数声明

接口说明

begin+end

返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器

rbegin+rend

返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的reverse_iterator,即begin的前一个位置

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

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位置的元素

erase

删除list position位置的元素

swap

交换两个list中的元素

clear

清空list中的有效元素

2.为什么使用迭代器?

容器类使用迭代器进行访问和遍历的主要原因包括以下几点:

  1. 抽象数据结构访问接口:通过迭代器,容器类可以提供一种统一的、抽象的方法来访问和操作容器中的元素。这样,无论容器内部的数据结构是什么,用户都可以使用相同的方式来访问和操作元素,提高了代码的可复用性和可维护性。
  2. 封装容器的内部实现细节:容器的内部实现可能采用各种不同的数据结构,例如数组、链表、树等。通过迭代器,容器可以隐藏内部实现细节,只提供迭代器的接口给用户使用,从而保护容器内部数据的完整性和安全性。
  3. 支持灵活的遍历方式:迭代器提供了多种灵活的遍历方式,例如正向遍历、反向遍历、随机遍历等。这使得用户可以根据实际需求选择最适合的遍历方式,提高了代码的灵活性和效率。
  4. 方便的算法和函数库使用:许多算法和函数库都是基于迭代器的,例如STL中的算法库、boost库等。通过使用迭代器,可以方便地在容器上应用这些算法和函数,提高了开发效率和代码的重用性。

综上所述,使用迭代器可以提供一种统一的、抽象的方法来操作容器中的元素,封装容器的内部实现细节,提供灵活的遍历方式,并支持方便的算法和函数库的使用。这使得容器的访问和遍历更加方便、灵活和高效

3.list的模拟实现

3.1完整代码

//ReverseIterator.h
#define _CRT_SECURE_NO_WARNINGS 1namespace bit
{template<class Iterator, class Ref, class Ptr>//Ref表示引用类型,Ptr表示指针类型struct ReverseIterator{typedef ReverseIterator<Iterator, Ref, Ptr> Self;//重命名Iterator _it;//成员ReverseIterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp = *this;--_it;return tmp;}Self& operator--(){++_it;return *this;}Self& operator--(int){Self tmp = *this;++_it;return tmp;}bool operator!=(const Self& s) const{return _it != s._it;}};
}
//list.h
#define _CRT_SECURE_NO_WARNINGS 1#pragma once#include <assert.h>
#include "ReverseIterator.h"namespace bit
{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& it) const{return _node != it._node;}bool operator==(const self& it) const{return _node == it._node;}};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;reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}iterator begin(){//return _head->_next;//C++单参数类型支持隐式转换return iterator(_head->_next);//这两种写法是一样的}iterator end(){//return _head;//C++单参数类型支持隐式转换//虽然两种写法都是一样的,不过这种写法能更加明确的告诉我们返回的是迭代器类型的对象return iterator(_head);//匿名对象}const_iterator begin() const{//return _head->_next;//C++单参数类型支持隐式转换return const_iterator(_head->_next);//这两种写法是一样的}const_iterator end() const{return _head;}void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _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(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}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函数insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;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;--_size;delete cur;return next;//因为迭代器失效问题所以要返回下一个迭代器//为什么失效?因为删除之后迭代器原来的指向失效,需要返回下一个节点作为新的迭代器}size_t size(){return _size;}private:Node* _head;size_t _size;};struct A{A(int a1 = 0, int a2 = 0):_a1(a1), _a2(a2){}int _a1;int _a2;};
}
//main.cpp
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include <list>
using namespace std;
#include "list.h"void Print(const bit::list<int>& lt)
{bit::list<int>::const_iterator it = lt.begin();while (it != lt.end()){//(*it)++;cout << *it << " ";++it;}cout << endl;
}void test_list1()
{bit::list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);//因为链表的底层不一样,所以我们需要对其iterator进行封装然后重载运算符bit::list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;Print(lt);
}void test_list2()
{bit::list<bit::A> lt;lt.push_back(bit::A(1, 1));lt.push_back(bit::A(2, 2));lt.push_back(bit::A(3, 3));lt.push_back(bit::A(4, 4));bit::list<bit::A>::iterator it = lt.begin();while (it != lt.end()){cout << it->_a1 << " " << it->_a2 << endl;++it;}cout << endl;
}void test_list3()
{bit::list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);lt.push_back(6);lt.push_back(7);lt.push_back(8);for (auto e : lt){cout << e << " ";}cout << endl;lt.pop_front();lt.pop_back();for (auto e : lt){cout << e << " ";}cout << endl;
}void test_list4()
{bit::list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);bit::list<int> lt1(lt);for (auto e : lt1){cout << e << " ";}cout << endl;bit::list<int> lt2;lt2.push_back(10);lt2.push_back(20);lt2.push_back(30);lt2.push_back(40);lt1 = lt2;for (auto e : lt1){cout << e << " ";}cout << endl;
}void test_list5()
{bit::list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);//bit::list<int> lt1(lt);//for (auto e : lt1)//{//	cout << e << " ";//}//cout << endl;bit::list<int>::reverse_iterator rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";++rit;}cout << endl;}void test_list6()
{bit::list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);bit::list<int>::iterator it = lt.begin();while (it != lt.end()){if (*it == 2){it = lt.erase(it);}cout << *it << " ";++it;}cout << endl;
}int main()
{test_list6();return 0;
}

3.2代码解析

4.list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:

vector

list

底层结构

动态顺序表,一段连续空间

带头节点的双向循环链表

随机访问

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

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

插入和删除

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

任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)

空间利用率

底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高

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

迭代器

原生态指针

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

迭代器失效

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

插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响

使用场景

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

需要大量插入和删除操作,不关心随机访问

 

相关文章:

list的使用和模拟实现

目录 1.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 2.为什么使用迭代器&#xff1f; 3.list的模拟实现 3.1完整代码 3.2代码解析 4.list与…...

Kubernetes 部署DolphinScheduler 创建租户失败

创建租户 报错创建租户失败。后台日志如下 源代码跟踪 org.apache.dolphinscheduler.api.service.impl.TenantServiceImpl / if hdfs startup if (PropertyUtils.getResUploadStartupState()) {createTenantDirIfNotExists(tenantCode); }需要将 resource.storage.type 置为…...

uniapp 获取 view 的宽度、高度以及上下左右左边界位置

<view class"cont-box"></view> /* 获取节点信息的对象 */ getElementRect() {const query uni.createSelectorQuery().in(this);query.select(".cont-box").boundingClientRect(res > {console.log(res);console.log(res.height); // 10…...

财务数据分析之现金流量表模板分享

现金流量表是我们常说的财务数据分析三表之一。它可以呈现一个企业的现金流情况&#xff0c;揭示企业经营管理健康状态&#xff0c;但在实际使用中却有总给人一种用不上、用不好的矛盾感。怎么才能把现金流量表做好&#xff1f;不如借鉴下大神的现金流量表模板。 下面介绍的是…...

日常BUG——通过命令行创建vue项目报错

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 在使用vue命令行创建一个vue项目时&#xff0c;出现一下的错误&#xff1a; vue create my…...

CSS3 新特性

圆角阴影文字阴影线性渐变变换&#xff08;transform&#xff09;背景rgba伪元素&#xff1a;伪类 伪元素区别动画&#xff08;animate&#xff09;...

微信记录---推荐系统---23/8/14 小总结

推荐系统---23/8/14 小总结 1. ACM推荐系统专题研讨会2.图神经网络推荐系统3.表1 模型效果对标:MovieLens 1M4.爬虫技术5.TF-IDF算法6.图 2 海量学术大数据推荐系统技术架构7.图 4 CADAL 平台推荐系统框架设计8.企业推荐系统发展概述MLR(Mixed Logistic Regression)DIEN(Deep…...

学习笔记整理-正则表达式-01-认识正则

一、基本认识 1. 什么是正则表达式 正则表达式(regular expression)描述了字符串"构成模式"&#xff0c;经常被用于检查字符串是否符合预定的格式要求。 用一个例子快速演示正则表达式基本使用方法&#xff1a;检查某个字符串是否是6位数字 // 要检查的字符串va…...

windows10/11 修改docker镜像存储目录

windows10/11 修改docker镜像存储目录 windows10/11 修改docker镜像存储目录查看docker的状态关闭所有正在运行的实例导出WSL子系统镜像注销现有的wsl重新创建wsl系统 windows10/11 修改docker镜像存储目录 docker默认pull的镜像在c盘&#xff0c;随着镜像的增加&#xff0c;C…...

AI黑马挑战赛,探索研发新趋势丨IDCF

随着AI的出现&#xff0c;获取知识的成本大幅降低&#xff0c;当DevOps与AI相结合时&#xff0c;必将产生全新的化学反应。不断涌现的AI新工具提醒我们&#xff0c;一个全新的研发工作范式正在逐渐形成。而DevOps的核心理念是敏捷协同&#xff0c;作为工程师&#xff0c;如何通…...

关于onload事件

onload事件是在网页中的所有内容&#xff08;包括图片、样式表、脚本等&#xff09;都加载完成后触发的事件。它常用于在页面加载完成后执行一些操作&#xff0c;例如初始化页面元素、绑定事件监听器等。 可以通过以下方式来使用onload事件&#xff1a; 在HTML标签中直接添加…...

合并单元格

需求&#xff1a; 合并 相同名称的产品 先说下elementUI合并单元格的方法&#xff0c;先计算好要合并的行数rowspan&#xff0c;return {rowspan&#xff0c;colspan}&#xff0c;其他的单元格return{0,0} getData(params) {//临时数组&#xff0c;存放产品名称相同的数量this…...

Spring Boot @Validated 验证注解的使用

1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency> 2、使用 2.1、非对象参数 参数如果是非对象格式&#xff0c;需要在controller类上面添…...

如何理解“对矩阵进行初等行变换不改变其列向量的线性关系”?

对矩阵A进行初等行变换相当于左乘一个可逆矩阵P。 把A看作是列向量组&#xff0c;若有Ax0&#xff0c;则其中的x就说明了列向量的线性关系&#xff1a; [ α 1 , α 2 , α 3 ] [ x 1 x 2 x 3 ] [ 0 ] \left[ \alpha_1 ,\alpha_2, \alpha_3 \right] \begin{bmatrix} x_1\\ x…...

书店行业小程序开发攻略

随着移动互联网的快速发展&#xff0c;小程序成为了各行各业的热门选择&#xff0c;包括书店行业。书店小程序的开发可以为书店提供在线销售渠道&#xff0c;提高销售额&#xff0c;增强用户粘性。本文将介绍如何从搭建到上线开发一款书店行业小程序。 首先&#xff0c;我们需要…...

情感分析工具: TextBlob 与 VADER 的对比

一、说明 在本文我们将看到&#xff0c;在情感分析方面&#xff0c;我们更喜欢哪个库。这取决于很多情况。例如。数据采集。在我们进行分析之前&#xff0c;让我们先看看这两个库是关于什么的。 二、亮相工具库 2.1. 工具库TextBlob介绍&#xff1a; 图像。TextBlob: Simplif…...

uft8和utf8mb4的区别

文章目录 1、Unicode字符集2、UTF-8 编码3、utf8mb3 字符集4、utf8mb4 字符集5、utf8mb3和utf8mb4的区别 1、Unicode字符集 Unicode&#xff08;统一码、万国码、单一码&#xff09;是计算机科学领域里的一项业界标准&#xff0c;包括字符集、编码方案等。Unicode 是为了解决传…...

针对低分辨率或小目标的卷积-SPDConv

针对低分辨率或小目标的卷积-SPDConv 摘要引言A New Building Block:SPD-Conv附录代码&#xff1a; 摘要 卷积神经网络在许多计算机视觉任务中取得了巨大成功。然而&#xff0c;在图像低分辨率或目标较小任务上&#xff0c;他们的性能迅速下降。在本文中&#xff0c;我们指出&…...

vue基础-vue监听当前屏幕大小做不同的操作

文章目录 前言一、代码如下&#xff1a;总结 前言 在vue项目开发过程中&#xff0c;有个需求&#xff0c;就是当屏幕大于1024时&#xff0c;我们默认为PC模式。小于1024时&#xff0c;我们默认为H5模式。但是有的界面我们想在PC和H5上面展示不同的数据&#xff0c;请求不同的接…...

Unity框架学习--3

单例模式基类 构造函数私有化&#xff0c;防止外部创建对象 提供一个属性给外部访问&#xff0c;这个属性就相当于是这个类的唯一对象 分为懒汉模式和饿汉模式 不继承MonoBehaviour的单例模式 public static MyUiManager Instance {get{if (instance null){instance new …...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...