【1++的C++初阶】之list

news2024/11/25 21:24:30

👍作者主页:进击的1++
🤩 专栏链接:【1++的C++初阶】

文章目录

  • 一,什么是list
  • 二,构造与析构
    • 2.1 结点结构
    • 2.2 链表结构
    • 2.3 迭代器结构
  • 三,部分重要接口的作用及其实现
    • 3.1 迭代器相关的接口
    • 3.2 list相关接口

一,什么是list

list是可以在常数范围内进行任意插入和删除的序列式容器。
list底层是前后循环链表,因此可以双向前后迭代。与其他序列式容器相比,list的最大缺陷是不支持任意位置的随机访问。并且list还需要一些额外的空间来保存结点与结点间的相关联信息。

二,构造与析构

2.1 结点结构

template<class T>
	struct list_node
	{
		list_node* prev;//指向上一个结点
		list_node* next;//指向下一个结点
		T data;
		//构造
		list_node(const T& val = T())
			:data(val)
			, prev(nullptr)
			, next(nullptr)
		{}
	};

在此结构中,定义出来了指向结点的前后指针,结点数据类型并对上述成员变量进行了初始化。

2.2 链表结构

template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
		//构造
		list()
		{
			_head = new Node;
			_head->prev = _head;
			_head->next = _head;
		}

      void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
			
		}

//拷贝构造

template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			_head = new Node;
			_head->prev = _head;
			_head->next = _head;
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

		//拷贝构造
		//现代写法
		list(const list<T>& lt)
		{
			_head = new Node;
			_head->prev = _head;
			_head->next = _head;
			list<T> tmp(lt.begin(), lt.end());
			std::swap(_head, tmp._head);
		}

       ~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
	private:
		Node* _head;	
	};

此结构中定义了头结点,并对头结点进行了初始化,使其指向上一个的指针指向自己,指向下一个的指针指向自己。
拷贝构造我们用的是现代写法,通过迭代器构造,构造出一个临时对象,再将其头结点指针进行交换。需要注意的是:在拷贝前都要进行初始化,防止其成为野指针。
在析构之前先将哨兵位头结点前的结点进行释放,因此就有了clear()函数,最后在析构时就只需将头结点释放。

2.3 迭代器结构

template<class T, class Ref, class Ptr>
	struct list_iterator
	{
		typedef list_iterator<T,Ref,Ptr> iterator;
		typedef list_node<T> Node;
		//申请一个结点指针
		Node* _node;
		//构造
		list_iterator(Node* node)
			:_node(node)
		{}
	};

list迭代器的本质就是一个指向结点的指针。先是申请结点指针,进行初始化,使其指向传过来的结点指针。

三,部分重要接口的作用及其实现

3.1 迭代器相关的接口

bool operator !=(const iterator& it)const
		{
			return _node != it._node;
		}

		bool operator == (const iterator& it)const
		{
			return _node == it._node;
		}

		Ref operator *()
		{
			return _node->data;
		}

		Ptr operator->()
		{
			return &(operator*());
		}

		iterator& operator++()
		{
			_node = _node->next;
			return *this;
		}

		iterator operator++(int)
		{
			iterator tmp = *this;
			_node = _node->next;
			return tmp;
		}

		iterator& operator--()
		{
			_node = _node->prev;
			return *this;
		}

		iterator operator--(int)
		{
			iterator tmp = *this;
			_node = _node->prev;
			return tmp;
		}

因为list迭代器是自定义类型,因此迭代器之间的一些操作,我们就必须要进行函数重载。我们解释几个比较重要的函数重载 。

   Ptr operator->()
		{
			return &(operator*());
		}

此重载所适合的环境:当list中存储的也是一个结构体是,此运算符就能够使用。
例:


  struct pos
  {
    int a;
    int b;
  };
  list<pos> lt;
  list<pos>::iterator it=lt.begin();
  it->a;

在此函数内部,返回了&(operator*()),而operator*()我们也进行了重载,返回的是结点数据–data,要是按此形式,那么此函数最终返回的就是data的地址。这与我们上述it->a不符合。原因在于,此处还有个隐藏的->,其最终形式为:it->data->a;这是编译器为了语法的可读性,而进行的的特殊处理。
在这里插入图片描述

说完->重载,我们在来说说++的重载。

iterator& operator++()//前置++
		{
			_node = _node->next;
			return *this;
		}

由于list的空间是不连续的,因此迭代器++,就是到下一结点。

3.2 list相关接口

inert的实现

iterator insert(iterator pos,const T& val)
		{
			Node* cur = pos._node;
			Node* newnode = new Node(val);
			Node* prev = cur->prev;
			prev->next = newnode;
			newnode->prev = prev;
			newnode->next = cur;
			cur->prev = newnode;
			return iterator(newnode);

		}

在这里插入图片描述
在这里插入图片描述
erase的实现

iterator erase(iterator pos)
		{
			assert(pos != end());
			Node* cur = pos._node;
			Node* prev = cur->prev;
			Node* next = cur->next;
			prev->next = next;
			next->prev = prev;
			delete cur;
			return iterator(next);
		}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

uniapp 微信小程序 Picker下拉列表数据回显问题

效果图&#xff1a; 1、template <template><view class"items select-box"><view class"items-text">品牌型号</view><picker change"bindBrandType" :value"brandIndex" :range"brandList"…

线性表之链表

1、链表概述 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 顺序表的存储位置可以用一个简单直观的公式表示&#xff0c;它可以随机存取表中任意一个元素&#xff0c;但插入和删除需要移动大量元素。链式…

【多线程】Synchronize关键字之对象锁和类锁

目录 类锁和对象锁的区别 类锁 对象锁 测试用例 1.m1()和m2()方法都加锁【都为非静态&#xff0c;都加锁互斥执行】 2.m1()加锁&#xff0c;m2()不加锁【都为非静态&#xff0c;互不影响】 3.m3()和m4()都加锁【都为静态&#xff0c;互斥】 4.m3()加锁&#xff0c;m4()不…

WPF快速开发(2):图标库知识点

文章目录 前言知识点windows资源Style:样式Setter:属性继承关系 Trigger:触发器 WPF层级划分数据绑定声明数据上下文绑定数据模板 前言 图标资源下载 iconfont 知识点 windows资源 Window.Resources&#xff1a;资源位置声明X:Key&#xff1a;资源Id&#xff0c;用于前端的…

ARM DAY3 点亮三盏灯

1.汇编代码 .text .global _start _start: //RCC初始化 RCC_INIT://设置GPIOE组使能ldr r0,0x50000A28ldr r1,[r0]orr r1,r1,#(0x1<<4)str r1,[r0]//设置GPIOF组使能 ldr r0,0x50000A28ldr r1,[r0]orr r1,r1,#(0x1<<5)str r1,[r0]//LED1灯初始化 LED1_INIT://设置…

WebLLM项目:在浏览器中运行LLM聊天机器人

大家好&#xff0c;基于LLM的聊天机器人可以通过前端访问&#xff0c;而且它们涉及到大量且昂贵的服务器端API调用。但如果可以让LLM完全在浏览器中运行——利用底层系统的计算能力呢&#xff1f;这样&#xff0c;LLM的全部功能都将在客户端可用——无需担心服务器的可用性、基…

算法竞赛入门【码蹄集新手村600题】(MT1020-1040)

算法竞赛入门【码蹄集新手村600题】(MT1020-1040&#xff09; 目录MT1021 %f格式符MT1022 小数、指数MT1023 进制乱炖MT1024 进制形式MT1025 八、十六进制MT1026 合并MT1027 整数逆序MT1028 四位数逆序MT1029 位数MT1030 最大公约数MT1031 最简分数MT1032 最小公倍数MT1033 多项…

LeetCode[327]区间和的个数

难度&#xff1a;Hard 题目&#xff1a; 给你一个整数数组 nums 以及两个整数 lower 和 upper 。求数组中&#xff0c;值位于范围 [lower, upper] &#xff08;包含 lower 和 upper&#xff09;之内的 区间和的个数 。 区间和 S(i, j) 表示在 nums 中&#xff0c;位置从 i 到 …

一文了解UML

目录 1 什么是UML? 2 UML视图&#xff08;UML View&#xff09; 2.1 用户视图&#xff08;Users View&#xff09; 2.2 结构视图&#xff08;Structural Views&#xff09; 2.3 行为视图&#xff08;Behavioral Views&#xff09; 2.4 环境视图&#xff08;Environmenta…

Vc - Qt - 自定义ComboBox

示例代码创建了一个名为ComboBoxWidget的自定义QWidget类&#xff0c;并在initUI方法中创建了一个垂直布局。然后将一个只读的QLineEdit和一个QPushButton添加到布局中。当按钮被点击时&#xff0c;会调用showMenu方法&#xff0c;该方法创建一个QMenu并添加选项。每个选项连接…

vite打包性能优化以及填坑

目录 前言 项目优化前 分析 优化 拆分包 去除debugger CDN 加速 按需导入 文件压缩 图片压缩 viteImagemin报错 填坑 坑1 坑2 总结 配置 前言 最近在使用 Vite4.0 构建一个中型前端项目的过程中&#xff0c;遇到了一些坑&#xff0c;也做了一些项目在构建生产环…

RepViT:从ViT的角度重新审视mobile CNN

文章目录 RepViT: Revisiting Mobile CNN From ViT Perspective摘要本文方法代码实验结果 RepViT: Revisiting Mobile CNN From ViT Perspective 摘要 近年来&#xff0c;与轻量级卷积神经网络(cnn)相比&#xff0c;轻量级视觉变压器(ViTs)在资源受限的移动设备上表现出了更高…

JVM系统优化实践(21):GC生产环境案例(四)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 前面说了一般应用的OOM情况&#xff0c;但是OOM不知发生在应用层&#xff0c;有时候专门负责运行Java的Tomcat也会偶尔罢工一下&#xff0c;抛出OOM异常。因为Tomcat本身也…

git在工作区和本地库的操作命令

本文介绍一些开发时&#xff0c;常用的在工作区和本地库之间的操作命令 一、提交修改内容到 本地库 工作树的修改内容要提交到本地库&#xff0c;首先需要先添加到缓存区stage&#xff0c;在commit到本地库。 # filename就是你修改后需要提交的文件 git add <filename>…

unity进阶--json的使用学习笔记

文章目录 unity自带的json使用方法第三方--LitJson的使用第一种使用方式第二种--使用jsonData unity自带的json使用方法 创建数据类 转化成json 解析json 第三方–LitJson的使用 第一种使用方式 数据类 创建和解析 第二种–使用jsonData 创建 解析

奇舞周刊第500期:TQL,巧用 CSS 实现动态线条 Loading 动画

记得点击文章末尾的“ 阅读原文 ”查看哟~ 下面先一起看下本期周刊 摘要 吧~ 奇舞推荐 ■ ■ ■ TQL&#xff0c;巧用 CSS 实现动态线条 Loading 动画 最近&#xff0c;群里有个很有意思的问题&#xff0c;使用 CSS 如何实现如下 Loading 效果&#xff1a; leaferjs&#xff0c…

docker安装redis启动异常问题

问题描述 启动redis容器报错如下 se > /sys/kernel/mm/transparent_hugepage/enabled as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled (set to madvise or never). 1:M 21 Ju…

Python - Opencv应用实例之树叶自动分割、标签及统计分析系统

Python - Opencv应用实例之树叶自动分割、标签及统计分析系统 本文通过Python+opencv 实现这样的需求:输出位置和角度(x, y, r),并标记出轮廓基于传统图像处理算法实现,算法原理:输入图像 -> 灰度化 -> 二值化 -> 形态学处理 -> 轮廓提取 -> 树叶中心定位 -…

docker系列5:docker安装nginx

传送门 前面介绍了docker的安装&#xff1a;docker系列1&#xff1a;docker安装 还有docker镜像加速器&#xff1a;docker系列2&#xff1a;阿里云镜像加速器 以及docker的基本操作&#xff1a; docker系列3&#xff1a;docker镜像基本命令 以及容器的基本命令&#xff1a;…

DRL(自用)

RL学习算法 基于策略的算法&#xff1a;这是最通用的优化类型。策略将状态映射到操作。学习策略的 RL 代理可以创建从当前状态到目标状态的动作轨迹 REINFORCE 是一种基于策略的算法。基于策略的算法&#xff0c;优势在于它们可以应用于各种强化学习问题&#xff1b;但是其样…