C++STL【list链表】

list

1. list介绍

  • list文档(非官方)
    官方文档
  • list是双向带头循环链表,它可以在常数范围内的任意位置进行插入和删除操作。
  • list的迭代器是双向迭代器(bidirectional iterator),它可以前后双向迭代。
    由容器的底层结构决定,STL迭代器有不同的种类:
    在这里插入图片描述
  • list的底层空间如下图所示:
    在这里插入图片描述
  • 正因list的底层空间如此,它相比其他容器:
    优点:在任意位置插入、删除元素的执行效率更高(相比vector、deque等);
    缺点:不支持位置的随机访问,要访问某个节点,需要迭代器迭代;需要开辟额外的空间来储存下一个节点、上一个节点的地址;缓存命中率低。

2. list的常用接口

  • 与vector一样,list的许多接口中有很多别名:
    在这里插入图片描述
  1. 构造函数(constructor)

    (constructor)功能
    explicit list (const allocator_type& alloc = allocator_type());默认构造函数
    explicit list (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());用n个val值初始化
    template <class InputIterator>
    list (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());
    用迭代器初始化(可以允许其他类型作为参数初始化)
    list (const list& x);拷贝构造函数
    list<int> lt1;
    list<int> lt2(3, 2);
    int nums[] = { 1,2,3 };
    list<int> lt3(arr, arr + 3);
    list<int> lt4(v3);
    
  2. 容量操作

    函数功能
    size_type size(); const返回有效元素个数
    bool empty(); const判断是否为空
    void resize (size_type n, value_type val = value_type());改变有效元素个数
  3. 迭代器

    函数功能
    iterator begin();
    const_iterator begin() const;
    返回容器开头的位置的迭代器
    iterator end();
    const_iterator end() const;
    返回容器最后一个有效元素的下一个位置的迭代器
    reverse_iterator rbegin();
    const_reverse_iterator rbegin() const;
    返回容器最后一个有效元素的位置的迭代器
    reverse_iterator rend();
    const_reverse_iterator rend() const;
    返回容器开头的前一个位置的迭代器

    关于list的迭代器:

    1. 迭代器一般是指针,在string和vector中,因为底层空间是连续的,所以它们的迭代器可以直接使用指针;但是list不行,因为它的空间不是连续的,是多块由指针连接的小空间。因此list的迭代器必须做出改变,即重新封装。

    2. list的迭代器如下:
      在这里插入图片描述
      list迭代器被重新封装成为一个类,它的成员变量是一个节点的类型的指针,指向节点;另外在迭代器类中,还实现了一系列运算符重载,如*/->/!=/==/++/--,使得其与别的容器的迭代器功能一致。

    3. 关于迭代器内运算符->的重载:

    重载operator->,编译器进行了特殊处理。

    struct A
    {A(int a1 = 0, int a2 = 0): _a1(a1), _a2(a2){ }int _a1;int _a2;
    };
    void Test()
    {list<A> la;A aa(1, 2);la.push_back(aa);list<A>::iterator it = la.begin();cout << it->_a1 << endl;
    }
    

    operator->返回的是A*it->_a1就等价于 A * _ a1,这不合语法,正确写法应该是it->->_a1,但是这么写很难看,于是编译器做了优化,自动替我们加上了一个->,于是我们只需写成这样即可:it->_ val

    1. 迭代器提供了一种不暴露容器底层设计的方法来访问容器内容。
  4. 访问元素

    函数功能
    reference front();
    const_reference front() const;
    访问链表开头一个元素
    reference back();
    const_reference back() const;
    访问链表最后一个元素
    int nums[] = { 1,2,3 };
    list<int> lt(arr, arr + 3);
    cout << lt.front() << endl;
    cout << lt.back() << endl;
    
  5. 修改操作

    函数功能
    void push_back (const value_type& val);尾插一个值
    void pop_back();尾删一个值
    void push_front (const value_type& val);头插一个值
    void pop_front();头删一个值
    insert在某个位置插入元素
    erase删除某个位置的元素
    void swap (list& x);交换两个list对象
    void clear();清空有效元素
  6. 链表操作
    STL还提供了一些链表操作,如sort、reverse等,但是不常使用,这里就不多介绍了,若要查看,请移步官方文档。

3. 模拟实现list(部分接口)

#pragma once
#include<iostream>
#include<assert.h>using namespace std;namespace Myspace
{template <class T>struct list_node{list_node(const T& value = T()): _next(nullptr), _pre(nullptr), _val(value){ }list_node<T>* _next;list_node<T>* _pre;T _val;};// 正向迭代器template<class T, class Ref, class Ptr>struct __list_iterator{typedef __list_iterator<T, Ref, Ptr> Self; // Self表示自己typedef list_node<T> Node;__list_iterator(Node* node = nullptr): _node(node){ }Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp = *this;_node = _node->_next;return tmp;}Self& operator--(){_node = _node->_pre;return *this;}Self operator--(int){Self tmp = *this;_node = _node->_pre;return tmp;}Ref operator*(){return _node->_val;}Ptr operator->(){return &(_node->_val);}bool operator!=(const Self& it) const{return it._node != _node;}bool operator==(const Self& it) const{return it._node == _node;}Node* _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;///// <构造>void CreatHead(){_head = new Node;_head->_next = _head->_pre = _head;}list(){CreatHead();}list(int n, const T& _value = T()){CreatHead();while (n--){push_back(_value);}}template<class InputIterator>list(InputIterator first, InputIterator last){CreatHead();while (first != last){push_back(*first);++first;}}list(const list<T>& lt){CreatHead();//for (auto e : lt)//{//	push_back(e);//}list<T> temp(lt.begin(), lt.end());this->swap(temp);}list<T> operator=(list<T> lt){if (lt._head != _head){swap(lt);}return *this;}///// <迭代器>iterator begin(){return _head->_next; // 单参数的构造函数,可以进行整型提升,Node* 提升为iterator}iterator end(){return _head;}const_iterator begin() const{return _head->_next; // 单参数的构造函数,可以进行整型提升,Node* 提升为iterator}const_iterator end() const{return _head;}///// <容量>size_t size(){size_t sz = 0;Node* cur = _head->_next;while (cur != _head){sz++;++cur;}return sz;}bool empty(){return _head == _head->_pre;}void resize(size_t n, const T& value = T()){size_t sz = size();if (n < sz){while (n < sz){pop_back();sz--;}}else{while (sz < n){push_back(value);sz++;}}}///// <访问>T& front(){return _head->_next->_val;}const T& front() const{return _head->_next->_val;}T& back(){return _head->_pre->_val;}const T& back() const{return _head->_pre->_val;}///// <删除、插入>void push_back(const T& value){insert(end(), value);}void pop_back(){erase(--end());}void push_front(const T& value = T()){insert(begin(), value);}void pop_front(){erase(begin());}iterator insert(iterator pos, const T& value = T()){Node* newnode = new Node(value); // 待插入的新节点Node* cur = pos._node; // 取出pos迭代器的节点newnode->_pre = cur->_pre;newnode->_next = cur;cur->_pre->_next = newnode;cur->_pre = newnode;return newnode;}iterator erase(iterator pos){assert(pos._node != _head);Node* cur = pos._node;Node* ret = cur->_next; // 保留一下返回值cur->_pre->_next = cur->_next;cur->_next->_pre = cur->_pre;delete cur;return ret;}void clear(){Node* cur = _head->_next;while (cur != _head){_head->_next = cur->_next;delete cur;cur = _head->_next;}_head->_next = _head->_pre = _head;}void swap(list<T>& lt){std::swap(lt._head, _head);}private:Node* _head;};
}

注意:

  1. 构造函数vector(int n, const T& value = T())接口需要重载多个(int/size_t/long),以防止创建对象时(vector<int> v(2,3);)编译器自动匹配到vector(InputIterator first, InputIterator last)这个接口。
    原因:编译器总会选择最匹配的接口。
  2. 在扩容时拷贝数据的时候,不要使用memcpy(上述代码的第151行),原因如下:
    如果模板实例化为string,那么此时就相当于memcpy(string1, string2, size),将两个string类memcpy,一定是浅拷贝,因为string类本身有个char*的指针,需要动态开辟空间,memcpy仅仅是将两个指针指向了同一块空间,并没有开辟新的空间。
    直接赋值即可,赋值会调用string自己的赋值运算符重载,它自己会实现深拷贝。
    不止是string,其他任何动态管理空间的类都是如此。

4. 迭代器失效

list的结构是链状表,正因为它不是一块连续的空间,它的迭代器失效问题没有string和vector多。

只有在删除数据的时候,才可能引起迭代器失效。

  • 链表的insert没有迭代器失效的问题!
    因为没有扩容,不需要挪动数据,位置没有改变,迭代器还是指向那个节点。

  • 但是earse有迭代器失效的问题!
    因为节点释放了,迭代器却依旧指向那个位置。
    STL为erase增添了返回值,我们用完erase后要接收它的返回值,它返回的是删除的节点的下一个节点。

`,将两个string类memcpy,一定是浅拷贝,因为string类本身有个char*的指针,需要动态开辟空间,memcpy仅仅是将两个指针指向了同一块空间,并没有开辟新的空间。
直接赋值即可,赋值会调用string自己的赋值运算符重载,它自己会实现深拷贝。
不止是string,其他任何动态管理空间的类都是如此。

4. 迭代器失效

list的结构是链状表,正因为它不是一块连续的空间,它的迭代器失效问题没有string和vector多。

只有在删除数据的时候,才可能引起迭代器失效。

  • 链表的insert没有迭代器失效的问题!
    因为没有扩容,不需要挪动数据,位置没有改变,迭代器还是指向那个节点。

  • 但是earse有迭代器失效的问题!
    因为节点释放了,迭代器却依旧指向那个位置。
    STL为erase增添了返回值,我们用完erase后要接收它的返回值,它返回的是删除的节点的下一个节点。

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

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

相关文章

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之RowSplit容器组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之RowSplit容器组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、RowSplit容器组件 将子组件横向布局&#xff0c;并在每个子组件之间插入一…

数据处理分类、数据仓库产生原因

个人看书学习心得及日常复习思考记录&#xff0c;个人随笔。 数据处理分类 操作型数据处理&#xff08;基础&#xff09; 操作型数据处理主要完成数据的收集、整理、存储、查询和增删改操作等&#xff0c;主要由一般工作人员和基层管理人员完成。 联机事务处理系统&#xff…

Common Sense Machines(CSM):立志成为图像生成适用于游戏引擎的3D资产AI产品

详细说明 Common Sense Machines&#xff08;CMS&#xff09;&#xff1a;立志成为图像生成适用于游戏引擎的3D资产AI产品-喜好儿aigc详细说明&#xff1a;https://heehel.com/CSM-3d 官方网站&#xff1a;https://www.csm.ai/ 使用体验网址&#xff1a;https://3d.csm.ai/ 来…

lowcode-engine接入编辑器

https://lowcode-engine.cn/site/docs/guide/create/useEditor 方案1 pnpm init pnpm add "alilc/create-elementlatest"pnpm create "alilc/element" editor-project-name选择编辑器 进入执行pnpm install命令安装包 pnpm start报错 pnpm add &qu…

苹果曝出两个 iOS 系统 0-Day 漏洞

最近&#xff0c;苹果公司发布了紧急安全更新&#xff0c;解决了两个 iOS 零日漏洞。这些漏洞存在于 iOS 内核&#xff08;CVE-2024-23225&#xff09;和 RTKit&#xff08;CVE-2024-23296&#xff09;中&#xff0c;威胁攻击者可利用其绕过内核内存保护&#xff0c;这就给了具…

解决vue项目本地开发完成后部署到服务器后报404的问题

一、如何部署 前后端分离开发模式下&#xff0c;前后端是独立布署的&#xff0c;前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可 我们知道vue项目在构建后&#xff0c;是生成一系列的静态文件 常规布署我们只需要将这个目录上传至目标服务器即可 /…

ChatGPT提问技巧——控制温度和TOP-P样本

ChatGPT提问技巧——控制温度和TOP-P样本 “控制温度和Top-P抽样”在自然语言处理中&#xff0c;控制温度是指通过调整生成文本的随机性和多样性&#xff0c;而Top-P抽样是一种生成文本的策略&#xff0c;它选择概率最高的前P个词作为候选词汇。这两个技术常用于生成文本的质量…

文本溢出隐藏 显示省略号,鼠标悬浮展示 el-tooltip(TooltipIsShowMixin封装)

目录 mixins 封装使用 TooltipIsShowMixin效果展示 mixins 封装 TooltipIsShowMixin.js export const TooltipIsShowMixin {data() {return {tooltipIsShow: false}},methods: {tooltipIsDisHandler(className) {this.$nextTick(() > {const dom document.querySelector…

PDF处理控件aspose.PDF功能演示:将 PDF 转换为 Word 文档

在 Web 应用程序中处理文档时&#xff0c;将 PDF 文件无缝转换为 Word 文档的能力是一项宝贵的资产。此任务不仅常见&#xff0c;而且对于文档转换器和编辑器、从编辑和协作到内容提取的各种应用程序来说也是必不可少的。在这篇博文中&#xff0c;我们将探讨如何使用 JavaScrip…

挑战杯 基于深度学习的植物识别算法 - cnn opencv python

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 MobileNetV2网络4 损失函数softmax 交叉熵4.1 softmax函数4.2 交叉熵损失函数 5 优化器SGD6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的植物识别算法 ** …

预览和真机调试无法连接服务器(报网络错误),开发者工具可以正常用

预览和真机调试无法连接服务器&#xff08;报网络错误&#xff09;&#xff0c;开发者工具可以正常用 方法&#xff1a; localhost替换为下面的ip&#xff0c;手机和电脑都链接同一个wifi // let RootPath http://127.0.0.1:8081;//或者http://localhost:8081let RootPath ht…

鸿蒙Harmony应用开发—ArkTS声明式开发(事件独占控制)

设置组件是否独占事件&#xff0c;事件范围包括组件自带的事件和开发者自定义的点击、触摸、手势事件。 在一个窗口内&#xff0c;设置了独占控制的组件上的事件如果首先响应&#xff0c;则本次交互只允许此组件上设置的事件响应&#xff0c;窗口内其他组件上的事件不会响应。 …

AndroidStudio连不上adb报错ADB Connection Error

之前笔者一直通过AndroidStudio来看日志&#xff0c;也一直用的一套自己的SDK&#xff0c;用了好几年了。 但是突然有一天&#xff0c;AndroidStudio启动后就弹出警告窗&#xff1a;ADB Connection Error&#xff0c;如下&#xff1a; 在Event Log面板还持续性的输出&#x…

C++——string类

前言&#xff1a;哈喽小伙伴们&#xff0c;从这篇文章开始我们将进行若干个C中的重要的类容器的学习。本篇文章将讲解第一个类容器——string。 目录 一.什么是string类 二.string类常见接口 1.string类对象的常见构造 2.string类对象的容量操作 3. string类对象的访问及遍…

微软亚太区AI智能应用创新业务负责人许豪,将出席“ISIG-AIGC技术与应用发展峰会”

3月16日&#xff0c;第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导&#xff0c;企智未来科技&#xff08;AIGC开放社区、RPA中国、LowCode低码时代&#xff09;主办。大会旨在聚合每一位产业成员的力量&#xff0c;深入探索A…

16 PyTorch 神经网络基础【李沐动手学深度学习v2】

1. 模型构造 在构造自定义块之前&#xff0c;我们先回顾一下多层感知机的代码。 下面的代码生成一个网络&#xff0c;其中包含一个具有256个单元和ReLU激活函数的全连接隐藏层&#xff0c; 然后是一个具有10个隐藏单元且不带激活函数的全连接输出层。 层和块 构造单层神经网咯…

智慧安防视频远程监控平台EasyCVR集成后播放只有一帧画面是什么原因?

智慧安防视频监控平台EasyCVR能在复杂的网络环境中&#xff08;专网、局域网、广域网、VPN、公网等&#xff09;将前端海量的设备进行统一集中接入与视频汇聚管理&#xff0c;平台可支持的接入协议包括&#xff1a;国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议…

【Power Apps】实现一个响应式的对话框功能

在我们开始之前需要把这里关一下&#xff0c;不然的话会影响响应式布局的效果。 首先我们添加一个垂直容器作为遮罩层。 遮罩层的宽高直接设置为跟随父元素即可&#xff0c;让遮罩层占满整个屏幕&#xff0c;再把填充色改为有一定透明度的黑色&#xff0c;形成遮罩效果。 然后…

【b站咸虾米】1 Vue介绍 2021最新Vue从基础到实例高级_vue2_vuecli脚手架博客案例

课程地址&#xff1a;【2021最新Vue从基础到实例高级_vue2_vuecli脚手架博客案例】 https://www.bilibili.com/video/BV1pz4y1S7bC/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 感觉尚硅谷的Vue看完忘得差不多了&#xff0c;且之前学过咸虾米的unia…

Codeforces Round 932 (Div. 2) --- C. Messenger in MAC --- 题解

C Messenger in MAC 题目大意&#xff1a; 思路解析&#xff1a; 答案计算为 , 可以发现当所选的几个信息固定后&#xff0c;其实后面的一项就变为b_max - b_min&#xff0c;得到了这个结论之后&#xff0c;其实我们可以直接把整个信息按照b进行排序&#xff0c;枚举l,r&am…