C++ 学习系列 -- std::list

news2025/1/21 2:51:17

一  std::list 介绍

       list 是 c++ 中的序列式容器,其实现是双向链表,每个元素都有两个指针,分别指向前一个节点与后一个节点

      链表与数组都是计算机常用的内存数据结构,与数组连续内存空间不一样的地方在于,链表的空间是不连续的,链表是将一块块不连续的内存串联起来使用。

    正是由于链表的内存不连续这一特点,所以不能像数组一样,可以根据位置随机的访问每个元素,而链表我们压根不知道每个元素的实际位置到底在哪块内存区域。

     查找某个元素需要遍历整个链表,直到找到目标元素位置,时间复杂度是 O(n);

    在链表中插入一个元素与删除一个元素的时间复杂度是 O(1);

二   c++ 中 stl 链表结构

1. list 结构

   list  结构 (借用侯捷老师的一张图片来):

  

  由上面的结构上可以看出,list 是一个循环链表,链表的尾端是一个空节点,不存储任何数据。

三   c++ 中 stl 链表使用

 1  构造函数

构造函数说明
list()空构造函数
list( size_type count, const T& value)初始化一个元素数量为 count 个的 value 元素
list( std::initializer_list<T> init)利用列表初始化 list
list( InputIt first, InputIt last)利用迭代器的起始于终止位置初始化 list

 2   容器修改

函数说明
clear() 清空所有元素
insert在指定位置插入元素
emplace在指定位置插入元素, 可以通过直接传入元素类的构造参数实现原地构造
erase移除指定元素
push_backappend 元素到链表的尾部
pop_back将链表尾部元素弹出
push_frontappend 元素到链表的头部
pop_front将链表头部元素弹出
emplace_backappend 元素到链表的尾部, 可以通过直接传入元素类的构造参数实现原地构造
emplace_frontappend 元素到链表的头部, 可以通过直接传入元素类的构造参数实现原地构造

 3  容器访问

函数说明
begin返回头部元素的迭代器
end返回尾部元素的迭代器
rbegin返回尾部元素的迭代器
rend返回头部元素的迭代器
front返回头部元素的引用
back返回尾部元素的引用

4  容器容量

函数说明
empty判断 list是否为空
size返回 list 存储元素的个数
#include<iostream>
#include<list>

int main()
{
     // 1. 构造函数
    std::list<int> list;
    auto iter = list.begin();
    std::cout << *iter << "--- " << std::endl;;

    // 2. 容器修改
    list.push_back(1);
    list.push_back(2);
    list.push_back(3);
    list.push_back(4);
    list.push_back(5);
    list.push_front(11);
    list.push_front(22);

    list.pop_back();
    list.pop_front();

    list.insert(list.begin(), 666);

    // 3. 容器访问
    for(auto iter = list.begin(); iter != list.end();iter++)
    {
        std::cout << *iter << " "; // 666 11 1 2 3 4
    }
    std::cout << "" << std::endl;

    for(auto iter = list.rbegin(); iter != list.rend();iter++)
    {
        std::cout << *iter << " "; // 4 3 2 1 11 666
    }
    std::cout << "" << std::endl;
    std::cout << "first: " << list.front() << ", finish: " << list.back() << std::endl; // first: 666, finish: 4

    // 4. 容器容量
    std::cout << "empyt: " << list.empty() << std::endl; // 0
    std::cout << "size: "<< list.size() << std::endl; // 6

    list.clear();

    std::cout << "empyt: " << list.empty() << std::endl; // 1
    std::cout << "size: "<< list.size() << std::endl; // 0
    return 0;
}

四  简单实现

  

// my_list.h

#include<memory>
#include<iostream>

template<typename T>
struct _List_Node
{
    typedef _List_Node node;

    _List_Node()
    {
        prev = nullptr;
        next = nullptr;
    }

    _List_Node(T& da):data(da)
    {
        prev = nullptr;
        next = nullptr;
    }

    _List_Node(T&& da):data(da)
    {
        prev = nullptr;
        next = nullptr;
    }

    ~_List_Node()
    {
        prev = nullptr;
        next = nullptr;
    }

    node* prev;
    node* next;
    T data;
};

template<typename T>
struct _List_Iterator
{
    typedef T valueType;
    typedef T& refrence;
    typedef T* pointer;

    typedef  _List_Node<T> node;


    _List_Iterator(node* val):data(val)
    {

    }

    _List_Iterator& operator++()
    {
        this->data = this->data->next;
        return *this;
    }

    _List_Iterator operator++(int)
    {
        _List_Iterator tmp = *this;
        ++(*this);
        return tmp;
    }

    _List_Iterator& operator--()
    {
        this->data = this->data->prev;
        return *this;
    }

    _List_Iterator operator--(int)
    {
        _List_Iterator tmp = *this;
        --(*this);
        return tmp;
    }

    T& operator*()
    {
        return this->data->data;
    }

    bool operator != (_List_Iterator& other)
    {
        return this->data != other->data;
    }

    bool operator == (_List_Iterator& other)
    {
        return this->data == other.data;
    }

    bool operator != (_List_Iterator&& other)
    {
        return this->data != other.data;
    }

    bool operator == (_List_Iterator&& other)
    {
        return this->data == other.data;
    }

    node*  data;
};

template<typename T>
class my_list
{
    typedef  _List_Node<T>  node;
    typedef  _List_Iterator<T> iterator;
public:
    my_list():count(0)
    {
        next_curr = new node;
        pre_curr = next_curr;

        finish = new node;
        next_curr->next = finish;
        finish->next = next_curr;

        pre_curr->prev = finish;
        finish->prev = pre_curr;
    }

    ~my_list()
    {
        node* tmp = pre_curr;
        while (tmp != nullptr) {
            node* tt = tmp->next;
            delete tmp;
            tmp = tt;
        }
    }

    void push_back(T& val)
    {
        std::cout << "count: " << count << std::endl;

        if(count == 0)
            next_curr->data = val;
        else {
            node* tmp = new node(val);
            tmp->next = next_curr->next;
            tmp->next->prev = tmp;
            next_curr->next = tmp;
            tmp->prev = next_curr;
            next_curr = next_curr->next;
        }
        count++;
    }

    void push_back(T&& val)
    {
        push_back(val);
    }

    void push_front(T& val)
    {
        if(count == 0)
            pre_curr->data = val;
        else {
            node* tmp = new node(val);
            tmp->prev = pre_curr->prev;
            pre_curr->prev->next = tmp;
            tmp->next = pre_curr;
            pre_curr->prev = tmp;

            pre_curr = pre_curr->prev;
        }
        count++;
    }

    void push_front(T&& val)
    {
        push_front(val);
    }

    void pop_back()
    {
        if(count == 0)
        {
            return;
        } else
        {
            node* tmp = next_curr;
            next_curr->prev->next = next_curr->next;
            next_curr->next->prev = next_curr->prev;
            next_curr = next_curr->prev;

            delete tmp;
            count--;
        }
    }

    void pop_front()
    {
        if(count == 0)
        {
            return;
        } else
        {
            node* tmp = pre_curr;
            finish->next = pre_curr->next;
            pre_curr->next->prev = finish;
            pre_curr = pre_curr->next;
            delete tmp;
            count--;
        }
    }

    int size()
    {
        return count;
    }

    iterator begin()
    {
        return iterator(pre_curr);
    }

    iterator end()
    {
        return iterator(finish);
    }

    iterator rbegin()
    {
        return iterator(finish->prev);
    }

    iterator rend()
    {
        return iterator(pre_curr->prev);
    }

    void insert(iterator pos, T& val)
    {
        node* tmp = new node(val);

        pos.data->prev->next = tmp;
        tmp->prev = pos.data->prev;
        tmp->next = pos.data;
        pos.data->prev = tmp;
        if(pos.data == pre_curr)
        {
            pre_curr = pre_curr->prev;
        }
        else if(pos.data == next_curr){
            next_curr = next_curr->next;
        }
        count++;
    }

    void insert(iterator pos, T&& val)
    {
        insert(pos, val);
    }

    template<typename ... Args>
    void emplace(iterator pos, Args... args)
    {
        node* tmp = new node(std::forward<Args>(args)...);
        pos.data->prev->next = tmp;
        tmp->prev = pos.data->prev->next;
        tmp->next = pos.data;
        pos.data->prev = tmp;
        count++;
    }

    void erase(iterator pos)
    {
        node* tmp = pos.data;
        tmp->prev = tmp->next;
        delete tmp;
        count--;
    }

    void clear()
    {
        while (pre_curr->next != finish) {
            pop_back();
        }
        count = 0;
    }

    T& front()
    {
        return pre_curr->data;
    }

    T& back()
    {
        return next_curr->data;
    }

    bool empty()
    {
        return count == 0;
    }

public:
    node* next_curr = nullptr;
    node* pre_curr = nullptr;
    node* finish = nullptr;
    int count;
};

// main.cpp
#include<iostream>
#include<my_list.h>

int main()
{
     // 1. 构造函数
    my_list<int> list;

    // 2. 容器修改
    list.push_back(1);
    list.push_back(2);
    list.push_back(3);
    list.push_back(4);
    list.push_back(5);
    list.push_front(11);
    list.push_front(22);

    // 22 11 1 2 3 4 5
    list.pop_back();
    list.pop_front();
    list.insert(list.begin(), 666);


    // 3. 容器访问
    for(auto iter = list.begin(); iter != list.end();iter++)
    {
        std::cout << *iter << " "; // 666 11 1 2 3 4
    }
    std::cout << "" << std::endl;

    for(auto iter = list.rbegin(); iter != list.rend();iter--)
    {
        std::cout << *iter << " "; // 4 3 2 1 11 666
    }
    std::cout << "" << std::endl;
    std::cout << "first: " << list.front() << ", finish: " << list.back() << std::endl; // first: 666, finish: 4

    // 3. 容器容量
    std::cout << "empty: " << list.empty() << std::endl; // 0
    std::cout << "size: "<< list.size() << std::endl; // 6

    list.clear();

    std::cout << "empyt: " << list.empty() << std::endl; // 1
    std::cout << "size: "<< list.size() << std::endl; // 0

    return 0;
}

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

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

相关文章

Springboot实现登录功能(token、redis、登录拦截器、全局异常处理)

登录流程&#xff1a; 1、前端调用登录接口&#xff0c;往接口里传入账号&#xff0c;密码 2、根据账号判断是否有这个用户&#xff0c;如果有则继续判断密码是否正确 3、验证成功后&#xff0c;则是根据账号&#xff0c;登录时间生成token&#xff08;用JWT&#xff09; 4、将…

64位Office API声明语句第111讲

跟我学VBA&#xff0c;我这里专注VBA, 授人以渔。我98年开始&#xff0c;从源码接触VBA已经20余年了&#xff0c;随着年龄的增长&#xff0c;越来越觉得有必要把这项技能传递给需要这项技术的职场人员。希望职场和数据打交道的朋友&#xff0c;都来学习VBA,利用VBA,起码可以提高…

企业使用SSL证书对于SEO有多重要

在当今竞争激烈的在线市场中&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;是企业获得更高排名和增加网站流量的关键。在SEO策略中&#xff0c;企业使用SSL证书已经成为多重不可忽视的重要因素。让我们一起探究企业使用SSL证书对于SEO的重要性。 首先&#xff0c;搜索引…

socket.error: [Errno 10049]错误

今天在pycharm运行rl_server_no_training.py欲启动服务器时&#xff0c;却出现如下错误 Traceback (most recent call last):File "xxx/rl_server_no_training.py", line 333, in <module>main()File "xxx/rl_server_no_training.py", line 326, in…

【C++】运算符重载 ⑧ ( 左移运算符重载 | 友元函数 / 成员函数 实现运算符重载 | 类对象 使用 左移运算符 )

文章目录 一、左移运算符重载1、友元函数 / 成员函数 实现运算符重载2、类对象 使用 左移运算符3、左移运算符 << 重载 二、完整代码示例 一、左移运算符重载 1、友元函数 / 成员函数 实现运算符重载 运算符重载 的正规写法一般都是 使用 成员函数 的形式 实现的 ; 加法…

DLRover - 小记

文章目录 关于 DLRover 关于 DLRover github : https://github.com/intelligent-machine-learning/dlrover DLOver使大型人工智能模型的分布式训练变得简单、稳定、快速和绿色。 它可以在分布式集群上自动训练深度学习模型。 它帮助模型开发人员专注于模型结构&#xff0c;而…

手把手教你从零开始腾讯云服务器部署(连接建站教程)

使用腾讯云服务器搭建网站全流程&#xff0c;包括轻量应用服务器和云服务器CVM建站教程&#xff0c;轻量可以使用应用镜像一键建站&#xff0c;云服务器CVM可以通过安装宝塔面板的方式来搭建网站&#xff0c;腾讯云服务器网txyfwq.com分享使用腾讯云服务器建站教程&#xff0c;…

双周回顾#001 - 火烧云

工作以来&#xff0c;许久未曾见过如此壮观的火烧云景观了。 文章 1、穿透的 DIV &#xff08;pointer-events&#xff09;1 pointer-events 是一个蛮有趣的 CSS3 属性&#xff0c;虽然主要是针对 SVG &#xff0c;但其中几个属性应用在 div 上也是颇有意思。 顾名思义&…

学会自我投资:美团四大名著之<高效能人士的七个习惯>

你有没有这些问题&#xff1f;如果有&#xff0c;那么本文也许对你有用。 受害者心理&#xff0c;如果有人对你说粗话&#xff0c;就怼回去。消极被动。 没有计划。没有目标。不会担心自己的行为带来的后果。随波逐流。及时行乐&#xff0c;做个玩世不恭者。 拖延。总是先做紧…

vue +element 批量删除

1.拿到当前勾选状态 在el-table里边去写 单选用第一个 多选用第二个 select"selectHandle" :当用户手动勾选数据行的 Checkbox 时触发的事件 select-all"selectHandle":当用户手动勾选全选 Checkbox 时触发的事件// 点击勾选选择器selectHandle(selection…

机器学习:决策树

决策树 决策树是一种基于树形结构的模型&#xff0c;决策树从根节点开始&#xff0c;一步步走到叶子节点&#xff08;决策&#xff09;&#xff0c;所有的数据最终都会落到叶子节点&#xff0c;既可以做分类也可以做回归。 特征选择 根节点的选择该用哪一个特征呢&#xff…

【python海洋专题十二】年平均的南海海表面温度图

【python海洋专题十二】年平均的南海海表面温度图 上期内容 南海水深图 本期内容 年平均的南海平面温度图 数据来源 NCEP/DOE Reanalysis II: NOAA Physical Sciences Laboratory NCEP/DOE Reanalysis II skt.skt.sfc.mon.ltm.nc Part01. 本文重点内容 前几期地形图&a…

SSM - Springboot - MyBatis-Plus 全栈体系(二十一)

第四章 SpringMVC 四、RESTFUL 风格设计和实战 1. RESTFul 风格概述 1.1 RESTFul 风格简介 RESTful&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量…

QT基础入门——QMainWindow与对话框QDialog

前言&#xff1a; Qt 并没有专门的菜单项类&#xff0c;只是使用一个QAction类&#xff0c;抽象出公共的动作。当我们把QAction对象添加到菜单&#xff0c;就显示成一个菜单项&#xff0c;添加到工具栏&#xff0c;就显示成一个工具按钮。用户可以通过点击菜单项、点击工具栏按…

visual studio解决bug封装dll库

1.速度最大化 O2 2.设置输出目录 配置属性/常规/输出目录 链接器/常规/输出dll文件 链接器/调试/输出程序数据库pdb文件 链接器/高级/导入库 3.输出X86 X64分别对应的dll、lib、pdb 然后修改更新说明 更新说明格式如下&#xff1a; 4.将库提交到FTP每日更新库文档下 和测试交接…

运维/全栈必备Window指令

运维/全栈必备Window指令 前言 大家好 我是寸铁 除了Linux有常用的命令 Windows也有 下面让我们一起来看看吧! 总共是40个命令&#xff0c;按照前缀大致划分成25个命令。 便于系统学习和掌握。 需要用到的快捷键&#xff1a; 复制键&#xff1a; ctrl insert退出键&#x…

JTAG/SWD接口定义

目录 1. ST-Link接口定义 2. ULINK2接口定义 为方便查阅&#xff0c;将ST-LINK和ULINK的JTAG和SWD接口定义总结如下&#xff1a; 1. ST-Link接口定义 Pin no. ST-LINK/V2 connector (CN3) ST-LINK/V2 function Target connection (JTAG) Target connection (SWD) 1 VA…

Linux:环境变量、地址空间

目录 一、环境变量 1、什么是环境变量 2、常见的环境变量 3、环境变量相关命令 二、地址空间 1、进程地址空间 2、虚拟地址空间 一、环境变量 1、什么是环境变量 首先先举个环境变量的例子&#xff1a; 我们在Linux中&#xff0c;运行ls、pwd之类的命令&#xff0c;直…

RabbitMQ学习笔记(下):延迟队列,发布确认高级,备份交换机

十、延迟队列 延迟队列 概念&#xff1a; 延迟队列使用场景&#xff1a; 流程图&#xff1a; 延迟队列整合Springboot 导入依赖&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot…

基于SSM的电脑硬件库存管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…