C++初阶:STL容器list的使用与初版自实现

目录

  • 1. list的接口与使用
    • 1.1 默认成员函数
    • 1.2 迭代器与容量相关成员函数
    • 1.3 存储数据操作相关成员函数
    • 1.4 其他list操作成员函数
  • 2. list的自实现
    • 2.1 list的自实现功能
    • 2.2 list的结点结构
    • 2.3 list的迭代器
    • 2.3 list的结构
    • 2.4 list迭代器的运算符重载
    • 2.5 list的成员函数
  • 3. const迭代器,operator->运算符重载与模板参数的应用
    • 3.1 const迭代器
    • 3.2 迭代器的operator->运算符重载

1. list的接口与使用

  1. list对标的是数据结构中的双向带头循环链表

1.1 默认成员函数

构造与拷贝构造

//无参构造
list<int> l1;
//指定个数值构造
list<int> l2(3, 100);
//迭代器区间构造
list<int> l3(l2.begin(), l2.end());
//拷贝构造
list<int> l4(l3);

赋值重载操作符

//给正在定义的对象使用赋值,会自动调用拷贝构造
list<int> l1(3,100);list<int> l2 = l1;list3<int> l3;ls = l1;

1.2 迭代器与容量相关成员函数

迭代器相关

//正向反向迭代器
list<int> l1;
l1.begin();
l1.rbegin();//const迭代器
l1.cbegin();
l1.crbegin();

容量大小相关

//list的现容量
list<int> l1;
l1.capacity();
//list的现存储数据长度
l1.size();
//理论上的最大长度
l1.max_size();

1.3 存储数据操作相关成员函数

数据操作相关

//返回list的头尾元素
list<int> l1;
l1.front();
l1.back();list<int> l2(3,10);
//给已存在list使用指定值赋值
//使用指定值
l1.assgin(4, 99);
//使用迭代器区间
l1.assgin(l2.begin(), l2.end());//头插,头删
l1.push_front(100);
l1.pop_front();//尾插,尾删
l1.push_back(100);
l1.pop_back();//指定位置插入
//在指定迭代器位置之前插入一个值
l1.insert(l1.begin(), 100);
//在指定迭代器位置之前插入n个数
l1.insert(l1.begin(), 3, 100);
//在指定迭代器位置之前插入一段迭代器区间
l1.insert(l1.beign(), l2.begin(), l2.end());//指定位置删除
//删除指定迭代器位置的值
l1.erase(v.begin());
//删除指定的一段迭代器区间
l1.erase(v.begin(), v.begin() + 2);//将两个list的结点交换
l1.swap(l2);//调整链表的容量大小
//n大时扩容,n小时不缩容
//将list扩容至长度为10,并将新增加的结点值赋予为10
l1.resize(10,80);//清空list的所有结点
l1.clear();

1.4 其他list操作成员函数

接合/转移:splice

//list之间的接合
list<int> l1(5, 10);
list<int> l2(5, 9);//将list2拼接到list1的指定迭代器位置
l1.splice(l1.begin() + 1, l2);//将l1上的一个指定迭代器位置结点拼接到l2上的指定迭代器位置
l2.splice(l2.begin(), l1, l1.end() - 1);//将l1上的一段迭代器区间拼接l2的指定位置上
l2.splice(l2.begin(), l1.begin(), l1.begin() + 2);

寻找指定值并移除:remove,去重:unique

list<int> l1;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);
//找到list中值等于3的结点并移除
l1.remove(3);//对list进行去重操作,只保留不同值
l1.unique();

排序与逆置

list<int> l1;
l1.push_back(3);
l1.push_back(2);
l1.push_back(1);//对list进行排序
//归并排序
l1.merge();
l1.sort();//将整个链表逆置
l1.reverse();

2. list的自实现

2.1 list的自实现功能

  1. 结点与迭代器类型的定义,创建
  2. 迭代器的一系列运算符的重载
  3. list的默认成员函数:构造,析构,赋值重载,拷贝构造,析构
  4. list的插入删除相关成员函数:push_back,pop_back,push_front,pop_front,insert,erase

复用关系
在这里插入图片描述

2.2 list的结点结构

//结点,struct默认成员函数为公有
template<class T>
struct ListNode
{//类型名typedef ListNode<T> Node;Node* _prev;Node* _next;T val;//构造函数:ListNode(T x = T()):val(x),_prev(nullptr),_next(nullptr){}
};

2.3 list的迭代器

//迭代器
template<class T>
struct __list_iterator
{//内置类型无法进行运算符重载typedef __list_iterator<T> self;typedef ListNode<T> Node;__list_iterator(Node* node):_node(node){}//将指针进行封装Node* _node;
}

2.3 list的结构

template<class T>
class list
{
public://typedef的作用域只在类域中typedef __list_iterator<T> iterator;typedef ListNode<T> Node;private:Node* Head;
};

2.4 list迭代器的运算符重载

1. ++,–

self& operator++()
{_node = _node->_next;return *this;
}self operator++(int)
{self tmp(_node);_node = _node->_next;return tmp;
}self operator--(int)
{self tmp(_node);_node = _node->_prev;return tmp;
}self& operator--()
{_node = _node->_prev;return *this;
}

2. 解引用,!=,==

//后续可能存在值的修改
T& operator*()
{return _node->val;
}//直接使用beign()的返回值作为参数
//形成中间临时变量,临时变量具有常性
//直接传引用会导致权限的放大
//self生成拷贝,self&权限放大
bool operator!=(const self& it)
{return _node != it._node;
}bool operator==(const self& it)
{return _node == it._node;
}

2.5 list的成员函数

1. 构造

void init_empty()
{Head = new Node;Head->_next = Head;Head->_prev = Head;
}list()
{init_empty();
}

2. 迭代器

//单参数的构造函数,支持隐式类型转换
iterator begin()
{return Head->_next;
}iterator end()
{return Head;
}

3. 随机插入删除

void insert(iterator pos, T val)
{//在pos之前插入Node* cur = pos._node;Node* pre = cur->_prev;Node* newnode = new Node(val);newnode->_prev = pre;newnode->_next = cur;cur->_prev = newnode;pre->_next = newnode;
}//指定删除会导致,迭代器失效,野指针
iterator erase(iterator pos)
{//会进行优化,直接使用end()返回的指针进行优化assert(pos != end());//删除当前位置Node* cur = pos._node;Node* pre = cur->_prev;Node* next = cur->_next;pre->_next = next;next->_prev = pre;delete cur;return next;
}

4. 头插,头删,尾插,尾删

void push_back(T val)
{insert(end(), val);
}void push_front(T val)
{insert(begin(), val);
}void pop_back()
{erase(--end());
}void pop_front()
{erase(begin());
}

5. clear与swap

void swap(list<T> s)
{std::swap(Head, s.Head);
}void clear()
{while (begin() != end()){pop_back();}
}

6. 拷贝构造,赋值,析构

//没有写const迭代器
list(list<T>& s)
{//链接环状链表init_empty();//没有const迭代器for (auto e : s){push_back(e);}
}list<T>& operator=(list<T> s)
{swap(s);return *this;
}~list()
{clear();delete Head;Head = nullptr;
}

3. const迭代器,operator->运算符重载与模板参数的应用

3.1 const迭代器

  1. 我们对list容器的数据结构对象进行修开操作时,除开list提供的接口外,想要进行对指定位置的结点进行修改,需要先从链表中拿到这一结点位置信息,而我们只能通过迭代器访问遍历的方式做到这一操作。
  2. 想要修改或者访问list的某一结点都是通过迭代器的方式进行的,而list的插入删除操作等接口也是通过迭代器从而实现的。
  3. 当list被const进行修饰,其不想内部的数据被修改,即对我们仅开放只读权限时,我想要对list进行遍历,普通的迭代器因为类型不匹配的原因我们无法进行调用。
  4. 因此,我们需要专门创建支持this指针指向内容被const修饰的迭代器,即只有访问权限无法对其指向进行更改操作的迭代器。
  5. const迭代器的其他操作行为都与普通相同,只是operator*操作符重载返回的值是const修饰的无法更改,所以我们独立去编写一份相似度极高的代码是非常低效的。
  6. 解决方式采用引入新的模板参数来做operator*返回值类型的区分。
template<class T, class Ref>
struct __list_iterator
{typedef __list_iterator<T, Ref> self;typedef ListNode<T> Node;Node* _node;__list_iterator(Node* node):_node(node){}//const T&/T&//根据不同的模板参数,返回类型也不同Ref operator*(){return _node->val;}//其他操作与普通迭代器相同//......
};//增加const迭代器后的list容器
template<class T>
class list
{
public://同一模板,传递模板参数不同,得到的迭代器不同typedef __list_iterator<T, T&> iterator;typedef __list_iterator<T, const T&> const_iterator;//const迭代器//const修饰的变量,表示其值不想不被改变const_iterator begin() const{return Head->_next;}const_iterator end() const{return Head;}void init_empty(){Head = new Node;Head->_next = Head;Head->_prev = Head;}list(){init_empty();}private:Node* Head;
};
  1. 创建const迭代器后,拷贝构造可以直接使用const修饰的参数,提高效率。

3.2 迭代器的operator->运算符重载

  1. operator->运算重载的意义:当list存储的结点数据为自定义类型,且自定义类型其自身并没有重载流插入运算符,我们又要对其结点内部的值进行访问与打印时,迭代器重载的operator->就可以让我们来进行自定义结点内部数据的访问。
template<class T, class Ref, class Ptr>
struct __list_iterator
{typedef __list_iterator<T, Ref, Ptr> self;typedef ListNode<T> Node;Node* _node;__list_iterator(Node* node):_node(node){}//返回结点的数据的地址,间接达到对自定类型结点内部数据的访问//const迭代器中对值的访问都要用const修饰,添加新的模板参数Ptr operator->(){return &_node->val;}//其他操作与普通迭代器相同//......
};//list结构
template<class T>
class list
{
public://同一模板,传递模板参数不同,得到的迭代器不同typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;private:Node* Head;
};struct A
{int _aa;int _bb;A(int aa = 1, int bb = 1):_aa(aa),_bb(bb){}
};zyc::list<A> l1;l1.push_back(A());
l1.push_back(A(2,3));
l1.push_back(A(2,2));auto it = l1.begin();
//operator->的调用被编译器优化为一个箭头
//原本调用逻辑:it->->_aa,it.operator->()._aa
//优化调用
cout << it->_aa << endl;

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

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

相关文章

双指针(滑动窗口)-算法刷题

一.移动零&#xff08;. - 力扣&#xff08;LeetCode&#xff09;&#xff09; 算法思想 &#xff1a; 设置两个指针left,right&#xff0c;将数组分为三块[0,left]为不为0的元素&#xff0c;[left1,right-1]为0元素&#xff0c;[right,num.size()-1]为未扫描的区域&#xff0c…

第四百二十二回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"自定义标题栏"相关的内容&#xff0c;本章回中将介绍自定义Action菜单.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在这里提到的…

day3-QT

1>使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函。将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是…

JS操作元素的内容

对象.innerText 属性 对象.innerHTML 属性 <body><div classbox>文字</div><script>//首先获取元素const box document.querySelector(.box)console.log(box.innerText)</script> </body> 1.元素innerText属性 将文本内容添加到标签任…

【Redis知识点总结】(六)——主从同步、哨兵模式、集群

Redis知识点总结&#xff08;六&#xff09;——主从同步、哨兵模式、集群 主从同步哨兵集群 主从同步 redis的主从同步&#xff0c;一般是一个主节点&#xff0c;加上多个从节点。只有主节点可以接收写命令&#xff0c;主节点接收到的写命令&#xff0c;会同步给从节点&#…

Java-SSM小区物业管理系统

Java-SSM小区物业管理系统 1.服务承诺&#xff1a; 包安装运行&#xff0c;如有需要欢迎联系&#xff08;VX:yuanchengruanjian&#xff09;。 2.项目所用框架: 前端:JSP、layui等。 后端:SSM,即Spring、SpringMvc、Mybatis等。 3.项目功能点: 1.业主功能: a.登录/退出登录 …

【投资学】作业

第20题 20.某一看涨期权和某一看跌期权的标的股票均为XYZ&#xff0c;两者的执行价格均为每股50美元&#xff0c;期限均为6个月。若投资者以4美元的价格购入看涨期权&#xff0c;当股票价格分别是40美元&#xff0c;45美元&#xff0c;50美元&#xff0c;55美元&#xff0c;60…

git 模拟队内协作

push 与 pull 命令需要登录。 凭据管理器都得是对应用户的。一台电脑上需要切换&#xff0c;删除再连接。 目录 一、前提条件二、流程三、命令如下四、注意事项&#xff08;先看这个&#xff09; 一、前提条件 项目主人仓库公开仓库里有一个文件&#xff0c;例如&#xff1a;h…

零代码编程:用kimichat批量重命名txt文本文件

一个文件夹中有很多个txt文本文件&#xff0c;需要全部进行重命名。 可以在kimichat中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个关于批量重命名txt文本文件的Python脚本&#xff0c;下面是具体步骤&#xff1a; D:\Best Seller Books 这个文件夹…

Java二阶知识点总结(七)SVN和Git

SVN 1、SVN和Git的区别 SVN是集中式的&#xff0c;也就是会有一个服务器保存所有代码&#xff0c;拉取代码的时候只能从这个服务器上拉取&#xff1b;Git是分布式的&#xff0c;也就是说每个人都保存有所有代码&#xff0c;如果要获取代码&#xff0c;可以从其他人手上获取SV…

mysql80-DBA数据库学习1

掌握能力 核心技能 核心技能 mysql部署 官网地址www.mysql.com 或者www.oracle.com https://dev.mysql.com/downloads/repo/yum/ Install the RPM you downloaded for your system, for example: yum install mysql80-community-release-{platform}-{version-number}.noarch…

STM32之HAL开发——系统定时器(SysTick)

系统定时器&#xff08;SysTick&#xff09;介绍 SysTick—系统定时器是属于 CM3 内核中的一个外设&#xff0c;内嵌在 NVIC 中。系统定时器是一个 24bit的向下递减的计数器&#xff0c;计数器每计数一次的时间为 1/SYSCLK&#xff0c;一般我们设置系统时钟 SYSCLK等于 72M。当…

C语言动态内存的管理

前言 本篇博客就来探讨一下动态内存&#xff0c;说到内存&#xff0c;我们以前开辟空间大小都是固定的&#xff0c;不能调整这个空间大小&#xff0c;于是就有动态内存&#xff0c;可以让我们自己选择开辟多少空间&#xff0c;更加方便&#xff0c;让我们一起来看看动态内存的有…

【大模型】在VS Code(Visual Studio Code)上安装中文汉化版插件

文章目录 一、下载安装二、配置显示语言&#xff08;一&#xff09;调出即将输入命令的搜索模式&#xff08;二&#xff09;在大于号后面输入&#xff1a;Configure Display Language&#xff08;三&#xff09;重启 三、总结 【运行系统】win 11 【本文解决的问题】 1、英文不…

音视频领域首个,阿里云推出华为鸿蒙 HarmonyOS NEXT 版音视频 SDK

近日&#xff0c;阿里云在官网音视频终端 SDK 栏目发布适配 HarmonyOS NEXT 的操作文档和 SDK&#xff0c;官宣 MediaBox 音视频终端 SDK 全面适配 HarmonyOS NEXT。 此外&#xff0c;阿里云播放器 SDK 也在华为开发者联盟官网鸿蒙生态伙伴 SDK 专区同步上线&#xff0c;面向所…

C-GMVAE

embedding w i l _i^l il​&#xff0c;a feature embedding w x f _x^f xf​ 辅助信息 一作Junwen Bai&#xff0c;他的文章不建议复现

产品经理方法论——MRD文档模板】

一、 文档格式 无要求 二、文档类型 PPT 三、文档框架 1. 市场说明 市场规模&#xff1a;市场规模决定最终的利润。我们对于直接产生现金流的产品通过交易额衡量市场规模&#xff0c;如果是间接产生现金流的产品我们通过用户量衡量市场规模。市场增速&#xff1a;随着时间…

stm32使用定时器实现PWM与呼吸灯

PWM介绍 STM32F103C8T6 PWM 资源&#xff1a; 高级定时器&#xff08; TIM1 &#xff09;&#xff1a; 7 路 通用定时器&#xff08; TIM2~TIM4 &#xff09;&#xff1a;各 4 路 例如定时器2 PWM 输出模式&#xff1a; PWM 模式 1 &#xff1a;在 向上计数 时&#xff0…

稀碎从零算法笔记Day22-LeetCode:两数相加

题型&#xff1a;链表 链接&#xff1a;2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;Leet 题目描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 …

MySQL临时表:临时存储数据的灵活利器

MySQL临时表&#xff1a;临时存储数据的灵活利器 MySQL临时表是处理数据时非常有用的工具&#xff0c;它提供了临时存储数据的能力&#xff0c;使得复杂查询、排序、聚合以及数据筛选变得更加高效和简单。在本文中&#xff0c;我们将深入探讨MySQL临时表的概念以及何时需要使用…