活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 一键部署Llama3大模型学习机 0代码一键部署,预装最新主流大模型Llama3与StableDiffusion
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 产品能力
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      STL:List的使用和模拟实现

      首页 知识中心 其他 文章详情页

      STL:List的使用和模拟实现

      2025-05-09 08:20:32 阅读次数:1

      const,list,vector,节点,迭代,链表

      一、List的介绍

      list的文档介绍

      1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

      2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

      3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。

      4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

      5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

      要注意的是,list开始就不支持下标访问了,所以要访问都要以迭代器为准

      void Print(const list<int>& l)
      {
      	//迭代去区间遍历
      	list<int>::const_iterator it = l.begin();
      	while (it != l.end())
      	{
      		cout << *it << " ";
      		++it;
      	}
      	cout << endl;
      	//范围for遍历
      	for (auto e : l)
      		cout << e << " ";
      	cout << endl;
      }

      二、List的使用注意事项 

      STL:List的使用和模拟实现

      博主觉得跟之前vector的基本上差不了多少,如果不会看文档用库里面的list的可以去看博主只管关于string和vector的使用。

      C++:String类的使用-CSDN博客

      C++:Vector的使用-CSDN博客

      下面直接介绍List使用中的易错点

      2.1 List的迭代器失效问题

              我们之前学习vector的时候,知道了insert和erase都有可能存在迭代器失效的问题,那list会出现这种情况吗??下面来进行分析

      STL:List的使用和模拟实现

      insert插入新节点的迭代器,因此insert不可能会出现失效的问题。

      STL:List的使用和模拟实现

         而earse必然会失效,因为该迭代器对应的节点被删除了。如果我们想继续用的话,就得利用返回值去更新迭代器,返回值是被删除元素的下一个位置的迭代器。

      2.2 List中sort的效率测试

      我们用一段代码来测试一下list中sort的性能

      void test_op()
      {
      	srand((unsigned int)time(NULL));
      	const int N = 1000000;
      	vector<int> v;
      	v.reserve(N);
      	list<int> lt1;
      	list<int> lt2;
      	for (int i = 0; i < N; ++i)
      	{
      		int e = rand();
      		lt1.push_back(e);
      		lt2.push_back(e);
      	}
      	// 拷贝到vector排序,排完以后再拷贝回来
      	int begin1 = clock();
      	for (auto e : lt1)
      	{
      		v.push_back(e);
      	}
      	sort(v.begin(), v.end());
      	size_t i = 0;
      	for (auto& e : lt1)
      	{
      		e = v[i++];
      	}
      	int end1 = clock();
      	//list调用自己的sort
      	int begin2 = clock();
      	lt2.sort();
      	int end2 = clock();
      	printf("vector sort:%d\n", end1 - begin1);
      	printf("list sort:%d\n", end2 - begin2);
      }

      STL:List的使用和模拟实现 会发现哪怕我先拷贝到vector排完再拷贝回去效率都比list的sort效率高,所以list的sort实际中意义不是很大!!

       三、模拟实现的注意事项

           还是跟之前模拟实现一样,先看看SGI版本的源码 ,list本质上是带头双向链表

      第一部分    链表节点

      STL:List的使用和模拟实现​

      第二部分   迭代器

      STL:List的使用和模拟实现​

      第三部分、链表

      STL:List的使用和模拟实现​

      这里我们可以先实现链表节点结构体 这里用sturct把权限放开。

      //节点的封装
      template<class T>
      struct list_node
      {
      	list_node<T>* _prev;
      	list_node<T>* _next;
      	T _data;
      
      	//节点的构造函数
      	list_node(const T& val = T())
      		:_prev(nullptr)
      		, _next(nullptr)
      		, _data(val)
      	{}
      };

      然后封装一个链表,将头结点作为自己的成员变量封装起来

      	template<class T>
      class list
      {
      	typedef list_node<T>  node;//typedef可以帮助我们简洁代码
      	private:
      		node* _head;
      	};

      下面开始进行我们的重中之重——迭代器 

      四、正向迭代器的实现

      2.1 正向迭代器的封装

            在学习Vector的时候,我们发现其实vector的迭代器就是一个原生指针,所以我们将他改了名字

      STL:List的使用和模拟实现​

            这得益于vector空间连续的特点,所以对指针进行加和减再进行解引用可以访问到我们想要的元素,但是链表可以吗?

       STL:List的使用和模拟实现​

           虽然看似我们好像用箭头连接起来了,但其实他们空间上是不连续的,那我们对一个节点指针进行加减,就很难说能不能找到下一个节点,更多的是找不到的情况

          那我们思考一样,如果我们要搞一个迭代器,我们希望怎么去得到我们的数据呢??我们希望我们解引用的时候,可以拿到他的data,希望++的时候,可以拿到他的next,--的时候,可以拿到他的prev。  那我们怎么去改变原生操作符的行为呢?答案就是运算符重载!所以我们可以将迭代器单独封装成一个类去管理节点,改变运算符的行为!!

             我们先进行实现,然后再慢慢分析

      	//封装迭代器
      	template<class T, class Ref, class Ptr>//Ref用于引用是否const,Ptr用于指针是否const
      	struct list_iterator
      	{
      		typedef list_node<T> node;
      		typedef list_iterator<T, Ref, Ptr>  self;
      		node* _node;
      
      		//迭代器的构造函数
      		list_iterator(node* n)//迭代器的构造
      			:_node(n)
      		{}
      		//实现*
      		Ref operator*() const
      		{
      			return _node->_data;
      		}
      		//实现->
      		Ptr operator->() const
      		{
      			return &operator*();    //本来是两个->,为了增强可读性,我们封装了这个函数 比如当我们存储的结构体解引用后有多个成员,那么我们可以通过箭头的直线去找到对应我们想要的成员	
      		}
      		//前置++
      		self& operator++()
      		{
      			_node = _node->_next;
      			return *this;
      		}
      		//后置++
      		self operator++(int)
      		{
      			self temp(*this);
      			++*this;
      			return temp;
      		}
      		//前置--
      		self& operator--()
      		{
      			_node = _node->_prev;
      			return *this;
      		}
      		//后置--
      		self operator--(int)
      		{
      			self temp(*this);
      			--*this;
      			return temp;
      		}
      		//!=
      		bool operator!=(const self& s) const
      		{
      			return _node != s._node;
      		}
      		//==
      		bool operator==(const self& s) const
      		{
      			return _node == s._node;
      		}
      	};

      第一个模版参数是类型,第二个模版参数是引用,第三个模版参数是指针

             Ref和Ptr是用来区分正常的迭代器和const修饰的迭代器,Ref是T&或者是const T&,这样可以在某些时候我们去限制data不能被修改。而Ptr是T*或者是const T*,重载箭头的作用是如果我们data存储的是一个自定义类型,这个时候如果直接解引用肯定是不行的,所以我们的箭头可以在解引用的时候先返回data的地址,然后我们就可以通过箭头去访问他不同的成员变量。

      下面举个data存的是自定义类型的例子

      STL:List的使用和模拟实现​

      2.2 迭代器的使用

      template<class T>
      class list
      {
      	typedef list_node<T>  node;//typedef可以帮助我们简洁代码
      public:
      	//正向迭代器
      	typedef list_iterator<T, T&, T*>   iterator;
      	typedef list_iterator<T, const T&, const T*>   const_iterator;
      	//可读可写正向迭代器
      	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);
      	}
      	private:
      		node* _head;
      	};

      这边我们用到了匿名对象。

      思考:这里的const迭代器为什么不能直接用const修饰普通迭代器??

      STL:List的使用和模拟实现​

             因为typedef碰到const的话,就不是简单的字符串替换  实际上你以为的const T* ,在这里变成了T*const ,因为迭代器我们是希望他可以进行++和--的,而我们只是不希望他指向的内容给改变,所以我们的const要修饰的是指针的内容,而不是修饰指针。

      五、list相关的成员函数

      3.1  构造函数

      STL:List的使用和模拟实现​

      1、默认构造函数

      STL:List的使用和模拟实现​

      因为无论如何都要有哨兵节点,所以我们直接封装一个

      	void empty_init()
      	{
      		_head = new node;
      		_head->_next = _head;
      		_head->_prev = _head;
      	}

      所以可以这么写

      	//默认构造函数
      	list()
      	{
      		empty_init();
      	}

      2、有参构造函数

      //有参构造函数
      list(size_t n, const T& val = T())
      {
      	empty_init();
      	for (size_t i = n; i > 0; --i)
      		push_back(val);
      }

       3、迭代器区间构造函数

      //迭代器区间构造函数
      template <class InputIterator>
      list(InputIterator first, InputIterator last)
      {
      	empty_init();
      	while (first != last)
      	{
      		push_back(*first);
      		++first;
      	}
      }

      4、拷贝构造的传统写法

      传统方法就是一个个拷贝过去

      //拷贝构造函数传统写法
      list(const list<T>& lt)
      {
      	empty_init();
      	for (auto e : lt)
      		push_back(e);
      }

      5、拷贝构造的现代写法+swap

            现代写法就是,我先创建一个临时对象让他利用被拷贝对象的迭代器构造出来,然后再交换,窃取革命成功,被利用完后的临时对象会在栈帧结束后被清除(典型的资本家思维)

      	//交换函数
      	void swap(list<T>& temp)
      	{
      		std::swap(_head, temp._head);
      	}
      	//拷贝构造函数的现代写法
      	list(const list<T>& lt)
      	{
      		empty_init();
      		list<T> temp(lt.begin(), lt.end());//复用迭代器区间构造,让别人构造好了,我再窃取革命成果
      		swap(temp);
      	}

      3.2 clear和析构函数

          list不像vector一样,不能直接用头指针delete,因为空间不连续,所以要一个个节点去delete,所以在这之前,我们可以先实现clear,clear的作用是把链表清空,只剩一个头节点,然我们的析构函数再复用clear,然后再单独delete头节点就行了!!

      	//clear 只留一个头节点
      	void clear()
      	{
      		iterator it = begin();
      		while (it != end())
      			it = erase(it);
      	}
      	//析构函数
      	~list()
      	{
      		clear();
      		delete _head;
      		_head = nullptr;
      	}

      3.3 赋值重载和assign

      STL:List的使用和模拟实现​

      STL:List的使用和模拟实现​

             assign和=的本质上都是,先将原来的空间的内容给清空,换成的内容。 只不过区别就是assign可以利用迭代器去控制被替换的范围,也可以自己去换成n个一样的元素。所以我们先实现assign,再实现=

      1、assign直接替换

      //assign(直接替换)
      void assign(size_t n, const T& val)
      {
      	clear();
      	for (size_t i = n; i > 0; --i)
      		push_back(val);
      }

      2、assign迭代器区间替换

      	//assign(迭代器区间替换)
      	template <class InputIterator>
      	void assign(InputIterator first, InputIterator last)
      	{
      		clear();
      		while (first != last)
      		{
      			push_back(*first);
      			++first;
      		}
      	}

      3、assign直接替换重载(防止间接寻址)

      STL:List的使用和模拟实现​

      思考:我们的本意是将lt2替换成5个2,我们发现我们调的竟然是迭代器区间构造的assign,为什么会这样呢?????     

            因为重载类型会优先找最匹配的,assign的第一个版本的n是size_t类型,我们传的整数默认是int所以会发生强制类型转化,而第二个版本恰好可以变成两个int,所以他会走迭代器区间版本。所以此时有两个方案,第一个方案是我们要在第一个参数后面加u,但是这不符合我们的使用习惯,所以我们可以采用第二个方案,写个重载版本。

      //assign重载版本  防止间接寻址
      void assign(int n, const T& val)
      {
      	clear();
      	for (size_t i = n; i > 0; --i)
      		push_back(val);
      }

      4、赋值重载传统写法 

      直接复用assign

      	// 赋值重载的传统写法
      	list<T>& operator=(const list<T>& lt)
      	{
      		assign(lt.begin(), lt.end());
      		return *this;
      	}

      5、赋值重载的现代写法

      list<T>& operator=(list<T> lt)
      {
      	swap(lt);//利用值传递拷贝的临时对象进行交换
      	return *this;
      }

      3.4 修改相关函数(Modifiers)

      1、empty、size

      //size
      size_t size() const
      {
      	size_t n = 0;
      	for (auto e : *this)
      		++n;
      	return n;
      }
      //empty
      bool empty() const
      {
      	return node->next == node;
      }

      2、insert

      我们先实现insert和erase,其他的就可以直接复用了

      //insert
      iterator insert(iterator pos, const T& val)
      {
      	node* cur = pos._node;//记录当前节点
      	node* prev = cur->_prev;//记录前驱节点
      	node* newnode = new node(val);//建立新节点
      	//开始改变指向
      	newnode->_next = cur;
      	cur->_prev = newnode;
      	prev->_next = newnode;
      	newnode->_prev = prev;
      	return iterator(newnode);
      }

      3、erase

      //erase
      iterator erase(iterator pos)
      {
      	assert(pos != end());//确保不是删除哨兵位置
      	node* prev = pos._node->_prev;
      	node* next = pos._node->_next;
      	prev->_next = next;
      	next->_prev = prev;
      	delete pos._node;
      	return iterator(next);//利用匿名对象返回
      }

      4、尾插尾删头插头删

      //pushback 尾插
      void push_back(const T& val)
      {
      	insert(end(), val);
      }
      //pushfront 头插
      void push_front(const T& val)
      {
      	insert(begin(), val);
      }
      //popback 尾删
      void pop_back()
      {
      	erase(--end());
      }
      //popfront 头删
      void pop_front()
      {
      	erase(begin());
      }

      5、resize

      //resize  如果n小于当前容量的大小,则内容将减少到前n个元素 当n大于容器大小时,则在末尾插入任意容量的内容。
      void resize(size_t n, const T& val = T())
      {
      	size_t sz = size();//记录当前的有效元素的个数
      	while (n < sz)
      	{
      		pop_back();
      		--sz;
      	}
      	while (n > sz)
      	{
      		push_back(val);
      		++sz;
      	}
      }

      六、反向迭代器的实现

      sgi版本下的反向迭代器,其实就是将构建一个反向迭代器的类将正向迭代器封装起来,这个时候正向迭代器的++就是反向迭代器的--

      template<class iterator, class Ref, class Ptr>
      struct list_reverse_iterator
      {
      	typedef list_reverse_iterator<iterator, Ref, Ptr> self;
      
      	//用正向迭代器去构造反向迭代器
      	list_reverse_iterator(iterator it)
      		:_cur(it)
      	{}
      	//解引用
      	Ref operator*() const
      	{
      		iterator temp = _cur;
      		--temp;
      		return *temp;
      	}
      	//实现->
      	Ptr operator->() const
      	{
      		return &operator*();
      	}
      	//前置++
      	self& operator++()
      	{
      		--_cur;
      		return *this;
      	}
      	//后置++
      	self operator++(int)
      	{
      		iterator temp(_cur);
      		--*this;
      		return temp;
      	}
      	//前置--
      	self& operator--()
      	{
      		++_cur;
      		return *this;
      	}
      	//后置--
      	self operator--(int)
      	{
      		iterator temp(_cur);
      		++*this;
      		return temp;
      	}
      	//不等于
      	bool operator!=(const self& s)
      	{
      		return _cur != s._cur;
      	}
      	//等于
      	bool operator==(const self& s)
      	{
      		return _cur == s._cur;
      	}
      	iterator _cur;
      };

      思考:为什么解引用的是前一个位置的元素???

      STL:List的使用和模拟实现​

      通过这个我们来看看vector下的反向迭代器代码:

      STL:List的使用和模拟实现​

               复用性很高,和list的区别就是因为是随机迭代器,所以多了+和-的接口,第二个就是不需要->,所以其实模版也可少传一个 

       七、list模拟实现的全部代码

      //c++喜欢ListNode驼峰法命名  为了和STL风格一致,我们也用小写
      //但是STL版本和java喜欢小写带_  
      namespace cyx
      {
      	//节点的封装
      	template<class T>
      	struct list_node
      	{
      		list_node<T>* _prev;
      		list_node<T>* _next;
      		T _data;
      
      		//节点的构造函数
      		list_node(const T& val = T())
      			:_prev(nullptr)
      			, _next(nullptr)
      			, _data(val)
      		{}
      	};
      	//封装迭代器
      	template<class T, class Ref, class Ptr>//Ref用于
      	struct list_iterator
      	{
      		typedef list_node<T> node;
      		typedef list_iterator<T, Ref, Ptr>  self;
      		node* _node;
      
      		//迭代器的构造函数
      		list_iterator(node* n)//迭代器的构造
      			:_node(n)
      		{}
      		//实现*
      		Ref operator*() const
      		{
      			return _node->_data;
      		}
      		//实现->
      		Ptr operator->() const
      		{
      			return &operator*();    //本来是两个->,为了增强可读性,我们封装了这个函数 比如当我们存储的结构体解引用后有多个成员,那么我们可以通过箭头的直线去找到对应我们想要的成员	
      		}
      		//前置++
      		self& operator++()
      		{
      			_node = _node->_next;
      			return *this;
      		}
      		//后置++
      		self operator++(int)
      		{
      			self temp(*this);
      			++*this;
      			return temp;
      		}
      		//前置--
      		self& operator--()
      		{
      			_node = _node->_prev;
      			return *this;
      		}
      		//后置--
      		self operator--(int)
      		{
      			self temp(*this);
      			--*this;
      			return temp;
      		}
      		//!=
      		bool operator!=(const self& s) const
      		{
      			return _node != s._node;
      		}
      		//==
      		bool operator==(const self& s) const
      		{
      			return _node == s._node;
      		}
      	};
      	template<class iterator, class Ref, class Ptr>
      	struct list_reverse_iterator
      	{
      		typedef list_reverse_iterator<iterator, Ref, Ptr> self;
      
      		//用正向迭代器去构造反向迭代器
      		list_reverse_iterator(iterator it)
      			:_cur(it)
      		{}
      		//解引用
      		Ref operator*() const
      		{
      			iterator temp = _cur;
      			--temp;
      			return *temp;
      		}
      		//实现->
      		Ptr operator->() const
      		{
      			return &operator*();
      		}
      		//前置++
      		self& operator++()
      		{
      			--_cur;
      			return *this;
      		}
      		//后置++
      		self operator++(int)
      		{
      			iterator temp(_cur);
      			--*this;
      			return temp;
      		}
      		//前置--
      		self& operator--()
      		{
      			++_cur;
      			return *this;
      		}
      		//后置--
      		self operator--(int)
      		{
      			iterator temp(_cur);
      			++*this;
      			return temp;
      		}
      		//不等于
      		bool operator!=(const self& s)
      		{
      			return _cur != s._cur;
      		}
      		//等于
      		bool operator==(const self& s)
      		{
      			return _cur == s._cur;
      		}
      		iterator _cur;
      	};
      	template<class T>
      	class list
      	{
      		typedef list_node<T>  node;//typedef可以帮助我们简洁代码
      	public:
      		//正向迭代器
      		typedef list_iterator<T, T&, T*>   iterator;
      		typedef list_iterator<T, const T&, const T*>   const_iterator;
              //typedef __list_const_iterator<T> const_iterator;不行
      		//反向迭代器
      		typedef list_reverse_iterator<iterator, T&, T*>    reverse_iterator;
      		typedef list_reverse_iterator<iterator, const T&, const T*>  const_reverse_iterator;
      		//可读可写正向迭代器
      		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()
      		{
      			empty_init();
      		}
      		//有参构造函数
      		list(size_t n, const T& val = T())
      		{
      		    empty_init();
      			for (size_t i = n; i > 0; --i)
      				push_back(val);
      		}
      		//迭代器区间构造函数
      		template <class InputIterator>
      		list(InputIterator first, InputIterator last)
      		{
      		     empty_init();
      			while (first != last)
      			{
      				push_back(*first);
      				++first;
      			}
      		}
      		//拷贝构造函数传统写法
      		/*list(const list<T>& lt)
      		{
      			empty_init();
      			for (auto e : lt)
      				push_back(e);
      		}*/
      		//交换函数
      		void swap(list<T>& temp)
      		{
      			std::swap(_head, temp._head);
      		}
      		//拷贝构造函数的现代写法
      		list(const list<T>& lt)
      		{
      			empty_init();
      			list<T> temp(lt.begin(), lt.end());//复用迭代器区间构造,让别人构造好了,我再窃取革命成果
      			swap(temp);
      		}
      		//assign(迭代器区间替换)
      		template <class InputIterator>
      		void assign(InputIterator first, InputIterator last)
      		{
      			clear();
      			while (first != last)
      			{
      				push_back(*first);
      				++first;
      			}
      		}
      		//assign(直接替换)
      		void assign(size_t n, const T& val)
      		{
      			clear();
      			for (size_t i = n; i > 0; --i)
      				push_back(val);
      		}
      		//assign重载版本  防止间接寻址
      		void assign(int n, const T& val)
      		{
      			clear();
      			for (size_t i = n; i > 0; --i)
      				push_back(val);
      		}
      		// 赋值重载的传统写法
      		list<T>& operator=(const list<T>& lt)
      		{
      			assign(lt.begin(), lt.end());
      			return *this;
      		}
      		// 赋值重载的现代写法
      		//list<T>& operator=(list<T> lt)
      		//{
      		//	swap(lt);//利用值传递拷贝的临时对象进行交换
      		//	return *this;
      		//}
      		//析构函数
      		~list()
      		{
      			clear();
      			delete _head;
      			_head = nullptr;
      		}
      		//size
      		size_t size() const
      		{
      			size_t n = 0;
      			for (auto e : *this)
      				++n;
      			return n;
      		}
      		//insert
      		iterator insert(iterator pos, const T& val)
      		{
      			node* cur = pos._node;//记录当前节点
      			node* prev = cur->_prev;//记录前驱节点
      			node* newnode = new node(val);//建立新节点
      			//开始改变指向
      			newnode->_next = cur;
      			cur->_prev = newnode;
      			prev->_next = newnode;
      			newnode->_prev = prev;
      			return iterator(newnode);
      		}
      		//erase
      		iterator erase(iterator pos)
      		{
      			assert(pos != end());//确保不是删除哨兵位置
      			node* prev = pos._node->_prev;
      			node* next = pos._node->_next;
      			prev->_next = next;
      			next->_prev = prev;
      			delete pos._node;
      			return iterator(next);//利用匿名对象返回
      		}
      		//pushback 尾插
      		void push_back(const T& val)
      		{
      			insert(end(), val);
      		}
      		//pushfront 头插
      		void push_front(const T& val)
      		{
      			insert(begin(), val);
      		}
      		//popback 尾删
      		void pop_back()
      		{
      			erase(--end());
      		}
      		//popfront 头删
      		void pop_front()
      		{
      			erase(begin());
      		}
      		//clear 只留一个头节点
      		void clear()
      		{
      			iterator it = begin();
      			while (it != end())
      				it = erase(it);
      		}
      		//resize  如果n小于当前容量的大小,则内容将减少到前n个元素 当n大于容器大小时,则在末尾插入任意容量的内容。
      		void resize(size_t n, const T& val = T())
      		{
      			size_t sz = size();//记录当前的有效元素的个数
      			while (n < sz)
      			{
      				pop_back();
      				--sz;
      			}
      			while (n > sz)
      			{
      				push_back(val);
      				++sz;
      			}
      		}
      		//empty
      		bool empty() const
      		{
      			return node->next == node;
      		}
      	private:
      		node* _head;
      		//用来初始化  类内部自己用,设私有
      		void empty_init()
      		{
      			_head = new node;
      			_head->_next = _head;
      			_head->_prev = _head;
      		}
      	};

          接口暂时就搞这些,如果后面有时间再写些比较复杂的接口,这一篇不太好理解,讲解不到位还请见谅

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.csdn.net/weixin_51142926/article/details/136531161,作者:✿༺小陈在拼命༻✿,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:DS初阶:二叉树的链式结构及实现

      相关文章

      2025-05-09 08:20:32

      STL:Vector的模拟实现

      STL:Vector的模拟实现

      2025-05-09 08:20:32
      memcpy , pos , vector , 失效 , 扩容 , 拷贝 , 迭代
      2025-05-08 09:04:49

      DS初阶:二叉树的链式结构及实现

      DS初阶:二叉树的链式结构及实现

      2025-05-08 09:04:49
      二叉树 , 右子 , 左子 , 节点 , 访问 , 递归 , 遍历
      2025-05-08 09:04:49

      DS初阶:二叉树的顺序结构及堆的实现

      DS初阶:二叉树的顺序结构及堆的实现

      2025-05-08 09:04:49
      堆排序 , 数组 , 算法 , 节点
      2025-05-08 09:04:49

      DS初阶:树及二叉树的相关概念

      树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

      2025-05-08 09:04:49
      二叉树 , 孩子 , 指针 , 结点 , 节点
      2025-05-08 09:04:25

      DS初阶:顺序表、链表经典OJ题(2)

      DS初阶:顺序表、链表经典OJ题(2)

      2025-05-08 09:04:25
      复杂度 , 思路 , 指针 , 数组 , 空间 , 结点 , 链表
      2025-05-08 09:03:38

      两数相加

      给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

      2025-05-08 09:03:38
      存储 , 数字 , 相加 , 示例 , 链表
      2025-05-08 09:03:07

      数据结构知识点

      数据结构知识点

      2025-05-08 09:03:07
      元素 , 结点 , 节点 , 链表 , 队列
      2025-05-07 09:12:52

      C语言:函数递归

      递归式一种解决问题的方法,在C语言中,递归就是自己调用自己。

      2025-05-07 09:12:52
      个数 , 函数 , 迭代 , 递归
      2025-05-07 09:12:52

      DS初阶:顺序表、链表相关OJ题(1)

      DS初阶:顺序表、链表相关OJ题(1)

      2025-05-07 09:12:52
      哨兵 , 思路 , 指针 , 结点 , 遍历 , 链表
      2025-05-07 09:09:52

      【C/C++笔记】:易错难点3 (二叉树)

      【C/C++笔记】:易错难点3 (二叉树)

      2025-05-07 09:09:52
      二叉树 , 结点 , 编号 , 节点 , 遍历
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33086

      阅读量

      4934828

      查看更多

      最新文章

      STL:Vector的模拟实现

      2025-05-09 08:20:32

      DS初阶:二叉树的链式结构及实现

      2025-05-08 09:04:49

      DS初阶:树及二叉树的相关概念

      2025-05-08 09:04:49

      DS初阶:顺序表、链表经典OJ题(2)

      2025-05-08 09:04:25

      DS初阶:顺序表、链表相关OJ题(1)

      2025-05-07 09:12:52

      【Linux 从基础到进阶】Kubernetes 集群搭建与管理

      2025-05-06 09:19:21

      查看更多

      热门文章

      python list转dict

      2023-04-18 14:16:25

      python 拆分list,按照对应位置重组

      2023-04-19 09:38:57

      python之list(学习笔记五)

      2023-03-20 10:30:01

      pytorch将Tensor转为list

      2023-04-19 09:22:23

      leetcode-单链表-23

      2023-03-07 07:47:14

      Node.js面试题:map(parseInt)

      2023-02-21 06:21:46

      查看更多

      热门标签

      linux java python javascript 数组 前端 docker Linux vue 函数 shell git 容器 spring 节点
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      LeetCode刷题:反转链表 与 链表中的中间节点

      python学习——迭代

      var、let、const之间的区别

      unordered_map和set

      高级指引——手动创建节点分组 Group

      Nacos 架构原理剖析,一条注册请求会经历哪些过程

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 权益商城
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 权益商城
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号