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 modififiers

1.2.6 list的迭代器失效

2. list的模拟实现

2.1 模拟实现list

2.2 list的反向迭代器


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的构造

构造函数(
(constructor)
接口说明
list (size_type n, const value_type& val = value_type())
构造的 list 中包含 n 个值为 val 的元素
list()
构造空的 list
list (const list& x)
拷贝构造函数
list (InputIterator fifirst, InputIterator last)
[fifirst, last) 区间中的元素构造 list

1.2.2 list iterator的使用

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

 

 

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

 1.2.3 list capacity

1.2.4 list element access

 

 1.2.5 list modififiers

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

1.2.6 list的迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针, 迭代器失效即迭代器所指向的节点的无效,即该节 点被删除了 。因为 list 的底层结构为带头结点的双向循环链表 ,因此 list 中进行插入时是不会导致 list 的迭代 器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响

2. list的模拟实现

2.1 模拟实现list

要模拟实现 list ,必须要熟悉 list 的底层结构以及其接口的含义,通过上面的学习,这些内容已基本掌握,现在我们来模拟实现list
#pragma once#include <iostream>
using namespace std;
#include <assert.h>namespace bite
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()): _prev(nullptr), _next(nullptr), _val(val){}ListNode<T>* _prev;ListNode<T>* _next;T _val;};/*List 的迭代器迭代器有两种实现方式,具体应根据容器底层数据结构实现:1. 原生态指针,比如:vector2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:1. 指针可以解引用,迭代器的类中必须重载operator*()2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)至于operator--()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前             移动,所以需要重载,如果是forward_list就不需要重载--4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()*/template<class T, class Ref, class Ptr>class ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到public:typedef Ref Ref;typedef Ptr Ptr;public://// 构造ListIterator(Node* node = nullptr): _node(node){}//// 具有指针类似行为Ref operator*() { return _node->_val;}Ptr operator->() { return &(operator*()); }//// 迭代器支持移动Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self temp(*this);_node = _node->_next;return temp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self temp(*this);_node = _node->_prev;return temp;}//// 迭代器支持比较bool operator!=(const Self& l)const{ return _node != l._node;}bool operator==(const Self& l)const{ return _node != l._node;}Node* _node;};template<class Iterator>class ReverseListIterator{// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的一个类型,而不是静态成员变量// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;public://// 构造ReverseListIterator(Iterator it): _it(it){}//// 具有指针类似行为Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){return &(operator*());}//// 迭代器支持移动Self& operator++(){--_it;return *this;}Self operator++(int){Self temp(*this);--_it;return temp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self temp(*this);++_it;return temp;}//// 迭代器支持比较bool operator!=(const Self& l)const{return _it != l._it;}bool operator==(const Self& l)const{return _it != l._it;}Iterator _it;};template<class T>class list{typedef ListNode<T> Node;public:// 正向迭代器typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;// 反向迭代器typedef ReverseListIterator<iterator> reverse_iterator;typedef ReverseListIterator<const_iterator> const_reverse_iterator;public:///// List的构造list(){CreateHead();}list(int n, const T& value = T()){CreateHead();for (int i = 0; i < n; ++i)push_back(value);}template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(*first);++first;}}list(const list<T>& l){CreateHead();// 用l中的元素构造临时的temp,然后与当前对象交换list<T> temp(l.begin(), l.end());this->swap(temp);}list<T>& operator=(list<T> l){this->swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}///// List的迭代器iterator begin() { return iterator(_head->_next); }iterator end() { return iterator(_head); }const_iterator begin()const { return const_iterator(_head->_next); }const_iterator end()const{ return const_iterator(_head); }reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}///// List的容量相关size_t size()const{Node* cur = _head->_next;size_t count = 0;while (cur != _head){count++;cur = cur->_next;}return count;}bool empty()const{return _head->_next == _head;}void resize(size_t newsize, const T& data = T()){size_t oldsize = size();if (newsize <= oldsize){// 有效元素个数减少到newsizewhile (newsize < oldsize){pop_back();oldsize--;}}else{while (oldsize < newsize){push_back(data);oldsize++;}}}// List的元素访问操作// 注意:List不支持operator[]T& front(){return _head->_next->_val;}const T& front()const{return _head->_next->_val;}T& back(){return _head->_prev->_val;}const T& back()const{return _head->_prev->_val;}// List的插入和删除void push_back(const T& val) { insert(end(), val); }void pop_back() { erase(--end()); }void push_front(const T& val) { insert(begin(), val); }void pop_front() { erase(begin()); }// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* pNewNode = new Node(val);Node* pCur = pos._node;// 先将新节点插入pNewNode->_prev = pCur->_prev;pNewNode->_next = pCur;pNewNode->_prev->_next = pNewNode;pCur->_prev = pNewNode;return iterator(pNewNode);}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){// 找到待删除的节点Node* pDel = pos._node;Node* pRet = pDel->_next;// 将该节点从链表中拆下来并删除pDel->_prev->_next = pDel->_next;pDel->_next->_prev = pDel->_prev;delete pDel;return iterator(pRet);}void clear(){Node* cur = _head->_next;// 采用头删除删除while (cur != _head){_head->_next = cur->_next;delete cur;cur = _head->_next;}_head->_next = _head->_prev = _head;}void swap(bite::list<T>& l){std::swap(_head, l._head);}private:void CreateHead(){_head = new Node;_head->_prev = _head;_head->_next = _head;}private:Node* _head;};
}///
// 对模拟实现的list进行测试
// 正向打印链表
template<class T>
void PrintList(const bite::list<T>& l)
{auto it = l.begin();while (it != l.end()){cout << *it << " ";++it;}cout << endl;
}// 测试List的构造
void TestBiteList1()
{bite::list<int> l1;bite::list<int> l2(10, 5);PrintList(l2);int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };bite::list<int> l3(array, array + sizeof(array) / sizeof(array[0]));PrintList(l3);bite::list<int> l4(l3);PrintList(l4);l1 = l4;PrintList(l1);
}// PushBack()/PopBack()/PushFront()/PopFront()
void TestBiteList2()
{// 测试PushBack与PopBackbite::list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);PrintList(l);l.pop_back();l.pop_back();PrintList(l);l.pop_back();cout << l.size() << endl;// 测试PushFront与PopFrontl.push_front(1);l.push_front(2);l.push_front(3);PrintList(l);l.pop_front();l.pop_front();PrintList(l);l.pop_front();cout << l.size() << endl;
}// 测试insert和erase
void TestBiteList3()
{int array[] = { 1, 2, 3, 4, 5 };bite::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto pos = l.begin();l.insert(l.begin(), 0);PrintList(l);++pos;l.insert(pos, 2);PrintList(l);l.erase(l.begin());l.erase(pos);PrintList(l);// pos指向的节点已经被删除,pos迭代器失效cout << *pos << endl;auto it = l.begin();while (it != l.end()){it = l.erase(it);}cout << l.size() << endl;
}// 测试反向迭代器
void TestBiteList4()
{int array[] = { 1, 2, 3, 4, 5 };bite::list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";++rit;}cout << endl;const bite::list<int> cl(l);auto crit = l.rbegin();while (crit != l.rend()){cout << *crit << " ";++crit;}cout << endl;
}

2.2 list的反向迭代器

通过前面例子知道,反向迭代器的 ++ 就是正向迭代器的 -- ,反向迭代器的 -- 就是正向迭代器的 ++ ,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。
template<class Iterator>
class ReverseListIterator
{// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的类型,而不是静态成员变量// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:typedef typename Iterator::Ref Ref;typedef typename Iterator::Ptr Ptr;typedef ReverseListIterator<Iterator> Self;
public://// 构造ReverseListIterator(Iterator it): _it(it){}//// 具有指针类似行为Ref operator*(){Iterator temp(_it);--temp;return *temp;}Ptr operator->(){ return &(operator*());}//// 迭代器支持移动Self& operator++(){
--_it;return *this;}Self operator++(int){Self temp(*this);--_it;return temp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self temp(*this);++_it;return temp;}//// 迭代器支持比较bool operator!=(const Self& l)const{ return _it != l._it;}bool operator==(const Self& l)const{ return _it != l._it;}Iterator _it;
};

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

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

相关文章

代码随想录第32天|122.买卖股票的最佳时机 II,55. 跳跃游戏 ,45. 跳跃游戏 II

122.买卖股票的最佳时机 II 122. 买卖股票的最佳时机 II 思路比较简单 class Solution {public int maxProfit(int[] prices) {int res0,sum0;for(int i0;i<prices.length-1;i){if(prices[i1]-prices[i]>0){sumprices[i1]-prices[i];}ressum>res?sum:res;}return …

笔记本重装win7旗舰版原版操作系统

正常开机的电脑&#xff1a;直接重装&#xff08;最简单&#xff0c;最快&#xff09;、Ghost重装、U盘重装、光盘重装、硬盘安装 不能正常开机的电脑&#xff1a;U盘重装、光盘重装、硬盘安装 注意&#xff1a; 1.windows7原版系统是不带任何驱动程序的&#xff0c;请事先准…

w ndows7旗舰版怎么重装系统,windows7旗舰版iso怎么安装

现在安装系统要求操作简单、方便。硬盘安装方式就是最简单、最方便的系统安装方法。保证电脑能进入系统的前提下&#xff0c;本地硬盘安装windows7旗舰版iso系统&#xff0c;能够让你快速体验新的windows7旗舰版iso系统。接下来详细讲解下安装windows7旗舰版iso系统的操作过程&…

w ndows7旗舰版网卡驱动,Ghost windows7 64位系统旗舰版网卡驱动工具推荐下载

雨林木风Ghost windows7 64位系统旗舰版网卡驱动工具可以使系统能够快速的链接网络&#xff0c;提供丰富的驱动文件&#xff0c;雨林木风Ghost windows7 64位系统旗舰版网卡驱动工具是很多的用户遇到问题都可以解决的一种工具&#xff0c;所以今天我们就来看看吧。 深度技术Gho…

windows7旗舰版安装过程

一&#xff0c;首先我提供一个windows7旗舰版<带激活工具>的下载地址: 7600_x86_zh-cn_Ultimate_DVD.iso 4 s5 T: O7 L. P* g如果连接错误就复制下面地址到迅雷thunder://QUFodHRwOi8vZG93bjIuZ2hvc3QyLmNuLzc2MDBfeDg2X3poLWNuX1VsdGltYXRlX0RWRC5pc29aWg泗水,泗水论坛,…

windows7系统之家旗舰版下载

肯定有很多朋友都想要了解windows7系统之家这款系统吧?毕竟这款系统可是非常值得一试的,如果大家想要使用这款系统的话,大家就需要事先了解它了,所以下面就给大家带来windows7系统之家下载吧。 ●系统之家ghost win7 x64 旗舰版v1610作品简述: 《系统之家ghost win7 x64 旗…

服务器 字体文件太大,网页的字体文件过大

今天写好了一个网页&#xff0c;开心的放到了云服务器&#xff0c;查看效果&#xff0c;结果发现忘记把字体文件拷过去。但是当字体文件拷过去后&#xff0c;再次访问网页时&#xff0c;网页加载变得十分缓慢&#xff0c;几分钟后才会将字体加载完成。 当时那个郁闷啊&#xff…

高等数学上册 第十章 重积分 第十一章 曲线积分与曲面积分 知识点总结

重积分 二重积分计算法&#xff1a; 直角坐标下&#xff1a;化为二次积分 { 如果图形是 X Y 型&#xff0c;则都可以&#xff0c;但要考虑哪个计算不定积分方便 如果图形既不是 X 也不是 Y 型&#xff0c;则要拆分 极坐标下&#xff1a; ∬ f ( x , y ) d x d y ∬ f ( ρ cos…

DevOps系列文章 之 Python基础

Python 基础篇&#xff08;一&#xff09; print( )函数、input( )函数 用 Python 来打印 Hello, world 你会惊奇地发现Python是如此的简洁与优雅。 # 打印Hello, world print(Hello, world) Hello, world# input()函数&#xff1a;接受一个标准输入数据&#xff0c;返回为s…

九龙证券|主力资金 矿业龙头尾盘净买超亿元

家用电器职业取得主力大手笔抢筹。 今天主力资金净流出260.84亿元&#xff0c;其间创业板净流出93.77亿元&#xff0c;沪深300成份股净流出40.64亿元。 申万一级职业中&#xff0c;今天有25个职业上涨&#xff0c;家用电器涨幅居首&#xff0c;达3.31%&#xff1b;其后煤炭、建…

九龙证券|又3个涨停,退市风险急升!

*ST新海退市危险急剧上升&#xff01; 到4月14日&#xff0c;*ST新海收盘价接连14个买卖日低于1元/股。按照退市新规&#xff0c;若*ST新海在接下来6个买卖日收盘价继续低于1元/股&#xff0c;将触及买卖类强制退市景象而终止上市&#xff0c;公司股票将不进入退市整理期。 面…

股票查询小程序_以龙虎榜数据为例

功能需求 1.程序启动后&#xff0c;给用户提供查询接口&#xff0c;允许用户重复查股票行情信息(用到循环&#xff09; 2.允许用户通过模糊查询股票名&#xff0c;比如输入“生物”&#xff0c;就把所有股票名称中包含“生物”的所有股票的信息打印出来 3.允许按收盘价,涨跌…

【龙虎榜小红牛分析系统G6.2】发布时间2021年03月14日

----更新功能如下 龙虎榜小红牛分析系统G6.20 #龙虎榜小红牛系统 #官方微信公众号&#xff1a;gxzfp888A.优化了数据库写入前先判断是否存在当天数据&#xff0c;避免因多次点入&#xff0c;重复写入数据问题&#xff0c;即一键下载龙虎和涨停数据。 B. 优化了再做&#xff0c…

上海亚商投顾:沪指窄幅震荡 ChatGPT概念股全线下挫

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数早盘小幅冲高&#xff0c;随后又震荡走低&#xff0c;午后一度集体翻绿&#xff0c;临近尾盘有所回升。Ch…

python 通达信板块_[python]沪深龙虎榜数据导入通达信的自选板块,并标注于K线图上...

将沪深龙虎榜数据导入通达信的自选板块,并标注于K线图上 原理:python读取前一次处理完的计算5日后涨跌幅输出的csv文件 文件名前加"[paint]" 安照通达信的画图文件和板块文件格式,输出文件 用通达信的导入功能,导入画图文件和板块文件即可 事前数据截图: 处理后…

[python]数据整理,将取得的众多的沪深龙虎榜数据整一整

将昨日取得的众多的沪深龙虎榜数据整一整 提取文件夹内所有抓取下来的沪深龙虎榜数据&#xff0c;整理出沪深两市&#xff08;含中小创&#xff09;涨幅榜股票及前5大买入卖出资金净值&#xff0c;保存到csv文件 再手动使用数据透视表进行统计 原始数据&#xff1a; 整理后数据…

攻防演练期间一次对某企业的渗透测试

免责声明 由于传播、利用本文章说黑客所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者说黑客不为此承担任何责任&#xff0c;一旦造成后果请自行承担&#xff01; 前言 某次攻防演练中&#xff0c;主办方只提供了目标…

应用TortoiseSVN的SubWCRev管理VisualStudio C#项目编译版本号

1、拷贝Porperties目录下的文件AssemblyInfo.cs生成副本AssemblyInfo.template.cs, 作为版本管理的模板文件。 2、修改模板文件中的想要管理的版本号信息 // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.5.0.$WCREV$")]//0.9.5…

c#之反射详解

总目录 文章目录 总目录一、反射是什么&#xff1f;1、C#编译运行过程2、反射与元数据3、反射的优缺点 二、反射的使用1、反射相关的类和命名空间1、System.Type类的应用2、System.Activator类的应用3、System.Reflection.Assembly类的应用4、System.Reflection.Module类的应用…

9. 解谜游戏

目录 题目 Description Input Notes 思路 暴力方法 递归法 注意事项 C代码&#xff08;递归法&#xff09; 关于DFS 题目 Description 小张是一个密室逃脱爱好者&#xff0c;在密室逃脱的游戏中&#xff0c;你需要解开一系列谜题最终拿到出门的密码。现在小张需要打…