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

【C++】list介绍以及模拟实现(超级详细)

欢迎来到我的Blog,点击关注哦💕

list的介绍和模拟实现

  • 前言
    • `list`介绍
    • 标准库容器` std::list` 与 `std::vector` 的优缺点
        • 缺点
  • `list`的基本操作
    • 构造函数
    • `list iterator`
    • `list capcacity`
    • `list modify`
  • `list`模拟实现
    • 存贮结构(双向带头循环)
    • `iterator`
      • `iterator`结构
      • `operator!=` `operator ==`
      • `operator++`
      • `operator--`
    • `list`数据结构
      • 构造函数
      • list的初始化
      • 节点初始化
      • 迭代器
    • `list modify`
      • insert
      • erase
      • 头插、头删、尾插、尾删
    • `list operator`
      • 交换
      • clear
  • 源码

前言

string vector的是存储是基于物理空间上连续的,而list是作为线性的链式结构,是值得学习的。

list介绍

  • std::list是C++标准模板库(STL)中的一个容器适配器,它内部实现为双向链表结构。
  • 这种设计使得std::list能够在常数时间内进行任意位置的插入和删除操作,这是其相对于其他序列容器如std::vector的显著优点。
  • std::list不支持随机访问,即无法直接通过索引来访问容器中的元素,这通常需要从头部或尾部开始迭代到目标位置.

标准库容器 std::liststd::vector 的优缺点

  • std::list: 作为一个双向链表,std::list 在插入和删除操作上具有优势,因为这些操作只涉及到改变相邻节点的指针,而不需要移动其他元素。此外,std::list 不需要预分配额外的内存,可以更好地处理动态内存分配,减少内存碎片.
  • std::vector: 作为一个动态数组,std::vector 提供了高效的随机访问能力,可以通过下标直接访问任意位置的元素,其访问效率为 O(1). 此外,std::vector 通常具有较高的空间利用率和缓存友好性,因为其元素在内存中是连续存储的.
缺点
  • std::list: 由于非连续的内存存储,std::list 在访问元素时效率较低,因为可能需要从头开始遍历链表。此外,每个节点都需要存储额外的指针信息,这增加了内存开销.
  • std::vector: 在 std::vector 的中间位置插入或删除元素可能会引起大量元素的移动,以维持内存的连续性,这会导致较差的性能。当 std::vector 的容量不足以容纳新增元素时,还需要进行动态扩容,这是一个成本较高的操作
vectorlist
底层
结构
动态顺序表,一段连续空间带头结点的双向循环链表
随 机
访 问
支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素 效率O(N)
插 入
删 除
任意位置插入和删除效率低,需要搬移元素,
时间复杂度为O(N),插入时有可能需要增容,
增容:开辟新空 间,拷贝元素,释放旧空间,导致效率更低
任意位置插入和删除效率高,不 需要搬移元
素,时间复杂度为 O(1)
插 入
删 除
底层为连续空间,不容易造成内存碎片,空间利用率 高,缓存利用率高底层节点动态开辟,小节点容易 造成内存碎片,空间利用率低, 缓存利用率低
迭 代 器原生态指针对原生态指针(节点指针)进行封装
迭 代 器
失 效
在插入元素时,要给所有的迭代器重新赋值,因为插入 元素有可能会导致重新扩容,致使原来迭代器失效,删 除时,当前迭代器需要重新赋值否则会失效插入元素不会导致迭代器失效, 删除元素时,只会导致当前迭代 器失效,其他迭代器不受影响
使 用
场 景
需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随 机访问

list的基本操作

构造函数

【C++】vector介绍以及模拟实现接口说明
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list()构造空的list
list (const list& x)拷贝构造函数
list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list

list iterator

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

函数声明接口说明
begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置

list capcacity

函数声明接口说明
empty检测list是否为空,是返回true,否则返回false
size返回list中有效节点的个数

list modify

函数声明接口说明
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中的有效元素

list模拟实现

存贮结构(双向带头循环)

  • 定义一个类(C语言:结构体)存储数据,作为指向下一个上一个的节点
namespace MyList
{//LIst节点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){}};
}

iterator

迭代器有两种实现方式,具体应根据容器底层数据结构实现:

  • 原生态指针,比如:vector string
  • 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
    1. 指针可以解引用,迭代器的类中必须重载operator*()
    2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载 oprator->()
    3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
    4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()

iterator结构

  • 三个模板参数
    1. 第一个模板参数控制类型
    2. 第二个模板参数控制返回值类型const 非const
    3. 第三个模板参数控制返回的list类的类型const 非const
  • Node* _node;需要定义一个指针,指向list节点
template<class T,class Ref,class ptr>struct _list_iterator{typedef _list_node<T> Node;typedef _list_iterator<T, Ref,ptr> self;Node* _node;};

operator!= operator ==

//重载operator!=
bool operator!=(const self& it)const 
{return _node != it._node;
}
//重载operator==
bool operator==(const self& it)const
{return _node == it._node;
}

operator++

//重载operator++(前置)
self& operator++()
{_node = _node->_next;return *this;
}
//重载operator++(后置)
self& operator++(int)
{self tmp(*this);_node = _node->_next;return tmp;
}

operator--

//重载operator--(前置)
self& operator--()
{_node = _node->_prev;return *this;
}
//重载operator--(后置)
self& operator--(int)
{self tmp(*this);_node = _node->_prev;return tmp;
}

operator* operator->

//重载operator*
Ref& operator* ()
{return _node->_val;
}
//重载operator->
ptr operator->()
{return _node->_val;
}

list数据结构

构造函数

list的初始化

  • 双向带带头循环
_head
//空list初始化
void empty_init()
{_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;
}

节点初始化

  • 默认构造函数
  • 默认构造函数
  • 用迭代器初始化
  • 拷贝构造函数
  • 赋值运算符重载
  • 赋值运算符重载
//默认构造函数
list()
{empty_init();
}
//默认构造函数
list(int n, const T& val = T())
{empty_init();while (n--){push_back(val);}}
//用迭代器初始化
template <class Iterator>list(Iterator first, Iterator last)
{empty_init();while (first != last){push_back(*first);++first;}
}
//拷贝构造函数
list(const list<T>& lt)
{empty_init();for (auto e : lt){push_back(e);}
}
//赋值运算符重载
list<T> operator=(list<T> lt)
{swap(lt);return *this;
}
//赋值运算符重载
~list()
{clear();delete _head;
}

迭代器

iterator begin()
{return _head->_next;
}
iterator end()
{return _head;
}
const_iterator begin()const
{return _head->_next;
}
const_iterator end()const
{return _head;
}

list modify

insert

  • 在pos位置插入节点,同数据结构是一样的,在这里面不过多赘述(可以参考)
//insert
iterator insert(iterator pos, const T& x)
{Node* newcode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newcode;newcode->_prev = prev;newcode->_next = cur;cur->_prev = newcode;++_size;return pos;
}

erase

  • 删除迫使位置的节点,同样(可以参考)
//erase
iterator erase(iterator pos)
{assert(pos._node != _head);Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;
}

头插、头删、尾插、尾删

  • 可以复用insert ersae STL标准模板库也是进行复用
// 头插
void push_front(const T& x)
{insert(begin(), x);
}
//头删
void pop_front()
{erase(begin());
}
//尾插
void push_back(const T& x)
{insert(begin());
}
//尾删
void pop_back()
{erase(--end());
}

list operator

交换

void swap(list<T> lt)
{std::swap(_head, lt._head);std::swap(_size, lt._size);}

clear

  • 析构函数也是利用了clear
//删除
void clear()
{iterator it = begin();while (it != end()){it = erase(it);++it;}}

源码

#pragma once
#include <iostream>
#include <assert.h>namespace MyList
{//节点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){}//重载operator*Ref& operator* (){return _node->_val;}//重载operator->ptr operator->(){return _node->_val;}//重载operator++(前置)self& operator++(){_node = _node->_next;return *this;}//重载operator++(后置)self& operator++(int){self tmp(*this);_node = _node->_next;return tmp;}//重载operator--(前置)self& operator--(){_node = _node->_prev;return *this;}//重载operator--(后置)self& operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}//重载operator!=bool operator!=(const self& it)const {return _node != it._node;}//重载operator==bool operator==(const self& it)const{return _node == it._node;}};//listtemplate<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;//空list初始化void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}//用n个val初始化list(int n, const T& val = T()){empty_init();while (n--){push_back(val);}}//用迭代器初始化template <class Iterator>list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);++first;}}//默认构造函数list(){empty_init();}//拷贝构造函数list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}//赋值运算符重载list<T> operator=(list<T> lt){swap(lt);return *this;}//析构函数~list(){clear();delete _head;}//删除void clear(){iterator it = begin();while (it != end()){it = erase(it);++it;}}//迭代器iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;}//void push_back(const T& x)//{//	Node* newcode = new Node(x);//	Node* tail = _head->_prev;//	tail->_next = newcode;//	newcode->_next = _head;//	newcode->_prev = tail;//	_head->_prev = newcode;//	++_size;//}// 头插void push_front(const T& x){insert(begin(), x);}//头删void pop_front(){erase(begin());}//尾插void push_back(const T& x){insert(begin());}//尾删void pop_back(){erase(--end());}//insertiterator insert(iterator pos, const T& x){assert(pos._node != _head);Node* newcode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newcode;newcode->_prev = prev;newcode->_next = cur;cur->_prev = newcode;++_size;return pos;}//eraseiterator erase(iterator pos){assert(pos._node != _head);Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}//大小size_t size()const{return _size;}//交换void swap(list<T> lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}private:Node* _head;size_t _size;};}

相关文章:

【C++】list介绍以及模拟实现(超级详细)

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; list的介绍和模拟实现 前言list介绍标准库容器 std::list 与 std::vector 的优缺点缺点 list的基本操作构造函数list iteratorlist capcacitylist modify list模拟实现存贮结构&#xff08;双向带头循环&#xff09;itera…...

从艺术创作到作物生长,农业AI迎来“GPT“时刻

&#xff08;于景鑫 国家农业信息化工程技术研究中心&#xff09;"GPT"一词早已不再神秘,其在文本、图像生成领域掀起的风暴正以摧枯拉朽之势席卷全球。人们惊叹于ChatGPT对话之智能、思维之敏捷,更对Stable Diffusion、Midjourney创作的艺术画作赞叹不已。而大语言模…...

前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线

本章响应小伙伴的反馈&#xff0c;除了算法自动画连接线&#xff08;仍需优化完善&#xff09;&#xff0c;实现了可以手动绘制直线、折线连接线功能。 请大家动动小手&#xff0c;给我一个免费的 Star 吧~ 大家如果发现了 Bug&#xff0c;欢迎来提 Issue 哟~ github源码 gitee…...

C#:通用方法总结—第15集

大家好&#xff0c;今天继续分享我们的通用方法系列。 下面是今天的通用方法&#xff1a; &#xff08;1&#xff09;这个通用方法为用文件流写数据 /// <summary> /// 用文件流写数据 /// </summary> /// <param name"data"></param> //…...

LoadRunner12 添加事务并添加检查点

1、先要添加事务开始函数lr_start_transaction("登陆事务");&#xff0c;在接口上方右击点击-插入-开始事务。输入事务名称&#xff1b; 2、在某个接口想法 右击点击-插入-结束事务&#xff0c;输入事务名称&#xff0c;与开始事务名称要保持一致&#xff0c;lr_end_…...

python中的文件

绝对路径和相对路径 一般情况下绝对路径就是从根目录开始描述的路径 相对路径就是相对于当前目录 . 没错,就是一个点,表示的是当前文件夹;.. 两个点表示的是上一层文件夹 os模块与os.path os 和 os.path 是两个非常重要的标准库模块,它们分别用于操作系统相关的功能操…...

Powerdesigner连接mysql数据库,逆向工程生成ER图 (保姆级教程:下载->连接->配置)看这一篇就够了

一、下载powerdesigner 下载的教程请看如下链接&#xff0c;我太懒了&#xff0c;直接借鉴&#xff01; 把别大佬的博客搬过来了嘿嘿~我真聪明&#xff01;ㄟ( ▔, ▔ )ㄏ 操作到完成汉化就好&#xff01;&#xff01;第5步不看了&#xff0c;别按那个走&#xff0c;因为新手…...

商家转账到零钱分销返佣申请方案及驳回处理办法

分销返佣场景是商家申请最多的场景&#xff0c;因而申请被驳回也是最多的&#xff0c;根据我们上万次成功开通商家转账到零钱的经验&#xff0c;当商家转账到零钱的分销返佣场景被驳回时&#xff0c;按照以下步骤&#xff0c;商家都可以快速过审&#xff1a; 一、分析驳回原因 …...

荟萃科技:国外问卷调查有没有实时更新的题库?

有的&#xff0c;口子查和渠道查都是。 口子查的题目都是国外的公司发放在网络上&#xff0c;都是实时发布&#xff0c;所以我们需要去国外的各大社交平台做题。 这些题目不是集中的&#xff0c;而是散布在网站里面&#xff0c;需要我们去找&#xff0c;都是老外上班实时发放…...

【课程总结】Day18:Seq2Seq的深入了解

前言 在上一章【课程总结】Day17&#xff08;下&#xff09;&#xff1a;初始Seq2Seq模型中&#xff0c;我们初步了解了Seq2Seq模型的基本情况及代码运行效果&#xff0c;本章内容将深入了解Seq2Seq模型的代码&#xff0c;梳理代码的框架图、各部分组成部分以及运行流程。 框…...

C++利用开发人员命令提示工具查看对象模型

1.跳转文件路径 cd 具体路径 2.输入c1 /d1 reportSingleClassLayout类名 文件名 操作示例如下图&#xff1a;...

白骑士的PyCharm教学高级篇 3.4 服务器部署与配置

系列目录 上一篇&#xff1a;白骑士的PyCharm教学高级篇 3.3 Web开发支持 在开发完成后&#xff0c;将代码部署到服务器上是一个关键步骤。PyCharm不仅提供了强大的本地开发支持&#xff0c;还为远程服务器配置与部署、自动化部署流程提供了便捷的工具和功能。本文将详细介绍如…...

数据库管理-第226期 内存至超线程(20240805)

数据库管理226期 2024-08-05 数据库管理-第226期 内存至超线程&#xff08;20240805&#xff09;1 CPU内缓存结构2 缓存与内存3 单核单线程4 超线程5 超线程的利弊总结 数据库管理-第226期 内存至超线程&#xff08;20240805&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xf…...

Django学习-数据迁移与数据导入导出

文章目录 一、数据迁移二、数据导入导出1. 数据导出2. 数据导入 一、数据迁移 数据迁移是将项目里定义的模型生成相应的数据表。主要的迁移指令如下&#xff1a; # 第一次生成自定义模型与django admin自带模型迁移文件&#xff0c;后续只生成新增模型迁移文件。后面加App名…...

【Nuxt】编程式导航和动态路由

编程式导航 navigateTo&#xff1a; 更多用法&#xff1a;navigateTo <template><div class"app-container"><button click"goToCategory">Category</button><NuxtPage/></div> </template> <script setup&…...

14. 计算机网络HTTPS协议(二)

1. 前言 上一章节中我们主要就 HTTPS 协议的前置知识进行介绍,下面会继续介绍 HTTPS 的通信过程以及抛出一些常见问题的探讨。因为候选人准备面试的时间和精力是比较有限的,我们在学习的过程要抓住重点,如果感觉对于细节缺乏了解,可以通过维基百科和查阅 StackOverflow 等…...

【算法设计题】实现以字符串形式输入的简单表达式求值,第2题(C/C++)

目录 第2题 实现以字符串形式输入的简单表达式求值 得分点&#xff08;必背&#xff09; 题解 1. 初始化和变量定义 2. 获取第一个数字并存入队列 3. 遍历表达式字符串&#xff0c;处理运算符和数字 4. 初始化 count 并处理加减法运算 代码详解 &#x1f308; 嗨&#xf…...

Kylin系列-入门

Kylin系列-入门 Apache Kylin是一个开源的分布式分析引擎&#xff0c;提供Hadoop/Spark之上的SQL查询接口及多维分析&#xff08;OLAP&#xff09;能力&#xff0c;以支持超大规模数据。以下是对Kylin系列的入门介绍&#xff1a; 一、基本概念 1. 定义 Apache Kylin是由eBa…...

力扣-46.全排列

刷力扣热题–第二十六天:46.全排列 新手第二十六天 奋战敲代码&#xff0c;持之以恒&#xff0c;见证成长 1.题目简介 2.题目解答 这道题目想了会,思路比较好想,但一直没调试成功,所以就参考了力扣官网的代码,积累一下回溯算法的实现和基本实现思路,即先试探后回溯,结果在下面…...

博物馆展厅AI交互数字人,解锁创新的文化交互体验

在智能化时代&#xff0c;博物馆展厅融入AI交互数字人&#xff0c;可以为游客给予实时交互的旅游服务&#xff0c;AI交互数字人可以承担智能引导、讲解、接待、客服与导游等多重角色&#xff0c;为游客塑造崭新的旅游体验。 AI交互数字人相比传统的录屏解说相比&#xff0c;AI…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践

前言&#xff1a;本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中&#xff0c;跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南&#xff0c;你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案&#xff0c;并结合内网…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案

引言 在分布式系统的事务处理中&#xff0c;如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议&#xff08;2PC&#xff09;通过准备阶段与提交阶段的协调机制&#xff0c;以同步决策模式确保事务原子性。其改进版本三阶段提交协议&#xff08;3PC&#xf…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版

1.题目描述 2.思路 当前的元素可以重复使用。 &#xff08;1&#xff09;确定回溯算法函数的参数和返回值&#xff08;一般是void类型&#xff09; &#xff08;2&#xff09;因为是用递归实现的&#xff0c;所以我们要确定终止条件 &#xff08;3&#xff09;单层搜索逻辑 二…...