C/C++ 入门(10)list类(STL)

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

                                                        欢迎来指教!

一、标准库中的list

1、了解

list:是一个双向带头循环链表,不支持随机访问(即下标访问),任意位置的插入删除效率高。

2、常用接口说明

a.常见的构造函数

list的构造函数
构造函数接口说明
list(size_t n, const T& val = t())构造n个值为val的list
list()构造空的list

list(const list& x)

拷贝构造
list(iterator first, iterator second)用[first, second)构造list

 b.迭代器

迭代器可以看作是一个指向节点的指针。

(rbegin和rend是反向迭代器,rbegin是指向了链表的尾部,rend是指向了链表的头部)

注意:

 begin,进行++操作是往后面走。

rbegin,进行++操作是往前面走。

c. Capacity

d.Element access

e.Modifiers

二、实现

 老规矩,我们还是先对结构进行分析。 

链表:除了一些对链表的基本操作之外,还需要有迭代器和节点。

1、框架 

#include <cstring>
#include <iostream>
using namespace std;

// 开辟一个自己的命名空间
namespace my
{
	// 链表节点
	// 迭代器
	// 链表
}

a.节点

// 链表节点
template<class T>
struct ListNode
{
	ListNode<T>* _prev;
	ListNode<T>* _next;
	T val;

	// 缺省参数,如果没有传参的话,默认是T类型的无参构造
	// 这样做是为了防止T是一个自定义类型
	ListNode(const T& e = T())
		:_prev(nullptr)
		,_next(nullptr)
		,val(e)
	{}
};

b.迭代器

其实这样的迭代器是不完整的,我们在后面会对其进行扩展。

template<class T>
struct NodeIterator
{
    // 对于节点和迭代器的重命名,方便书写
	typedef ListNode<T> Node;// 节点	
	typedef NodeIterator<T> Self; // 迭代器

	Node* _node;
    
    // 迭代器是用节点的指针来进行构造的
	NodeIterator(Node* node)
		:_node(node)
	{}
};

c.链表

// 链表
// list是一个带头双向循环链表
template<class T>
class list
{
	typedef ListNode<T> Node;// 节点
public:
	typedef NodeIterator<T, T&, T*> iterator;// 迭代器
private:
	Node* _head;// 链表的头部
	size_t _size;// 链表的长度
};

2、节点

其实节点这部分没有什么可以讲解的。唯一一个要理解的就是这个(const T& e = T())。

//const T& e = T()
// 首先T()是一个匿名对象的写法
// 为什么我们需要用到一个匿名对象,而不是一个const T& e = 值?
// 1、我们不知道T是什么类型,不知道值可以设成一个什么类型的值
// 2、如果我们设置成一个内置类型,而T是一个自定义类型的话,类型不匹配
ListNode(const T& e = T())
		:_prev(nullptr)
		,_next(nullptr)
		,val(e)
	{}

3、迭代器 

 我之前框架里所写的就是老版本的迭代器。

新版本里面的迭代器主要添加了两个新的模板变量(Ref,Ptr),引入的这两个变量是对解引用和引用的重写。

思考题:怎么写const版本的迭代器呢?

答:新版本写法的迭代器可以直接这么写(以int为例):

NodeIterator<int, const int&, const int*>

思考题:反向迭代器怎么实现的?

标准库里面的begin()和end() 与 rbegin()和rend()采用的是对称法。

// 迭代器
// 新版本
// 链表迭代器:模仿指针的行为
// Ref:引用,Ptr指针
template<class T, class Ref, class Ptr>
struct NodeIterator
{
	typedef ListNode<T> Node;// 节点	
	typedef NodeIterator<T, Ref, Ptr> Self; // 迭代器

	Node* _node;

	NodeIterator(Node* node)
		:_node(node)
	{}
	// 前置++
	Self& operator++()
	{
		_node = _node->_next;
		return *this;   
	}
	// 后置++
	Self& operator++(int)
	{
		Self tmp(*this);
		_node = _node->_next;
		return tmp; 
	}
	// 前置--
	Self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}
	// 后置--
	Self& operator--(int)
	{
		Self tmp(_node);
		_node = _node->_prev;
		return tmp;
	}
	// 解引用
	Ref operator*()
	{
		return _node->val;
	}
	// -> 
	Ptr operator->()
	{
		return &_node->val;
	}
	// ==
	bool operator==(const Self& s)
	{
		return _node == s._node;
	}
	// !=
	bool operator!=(const Self& s)
	{
		return !(*this == s); 
	}
};
 老版本:缺点:无法实现const的迭代器
 链表迭代器:模仿指针的行为
//template<class T>
//struct NodeIterator
//{
//	typedef ListNode<T> Node;// 节点
//	typedef NodeIterator<T> Self; // 迭代器
//
//	Node* _node;
//
//	NodeIterator(Node* node)
//		:_node(node)
//	{}
//	// 前置++
//	Self& operator++()
//	{
//		_node = _node->_next;
//		return *this;   
//	}
//	// 后置++
//	Self& operator++(int)
//	{
//		Self tmp(*this);
//		_node = _node->_next;
//		return tmp; 
//	}
//	// 前置--
//	Self& operator--()
//	{
//		_node = _node->_prev;
//		return *this;
//	}
//	// 后置--
//	Self& operator--(int)
//	{
//		Self tmp(_node);
//		_node = _node->_prev;
//		return tmp;
//	}
//	// 解引用
//	T& operator*()
//	{
//		return _node->val;
//	}
//	// ==
//	bool operator==(const Self& s)
//	{
//		return _node == s._node;
//	}
//	// !=
//	bool operator!=(const Self& s)
//	{
//		return !(*this == s); 
//	}
//
//	// -> 
//	T* operator->()
//	{
//		return &_node->val;
//	}
//};

// 反向迭代器
template<class Iterator, class Ref, class Ptr>
struct Reverse_iterator
{
	typedef Reverse_iterator<Iterator, Ref, Ptr> Self;
	Iterator _it;

	Reverse_iterator(Iterator it)
		:_it(it)
	{}

	Ref operator*()
	{
		Iterator tmp(_it);
		return *( -- tmp);
	}
	Ptr operator->()
	{
		//return &_it.operator->();
		return &(_it.operator*());
	}
	Self& operator++()
	{
		_it -- ;
		return *this;
	}
	Self& operator--()
	{
		_it ++;
		return *this;
	}
	bool operator!=(const Self& s)
	{
		return _it != s._it;
	}
};

 

 4、链表

// 链表
template<class T>
class list
{
	typedef ListNode<T> Node;
public:
	typedef NodeIterator<T, T&, T*> iterator;
	typedef NodeIterator<T, const T&, const T*> const_iterator;
	// 构造函数
	list ()
		:_size(0)
	{
		_head = new Node;
		_head -> _next = _head;
		_head -> _prev = _head;
	}
	list (size_t n, const T& val = T())
		:_size(0)
	{
		_head = new Node;
		_head -> _next = _head;
		_head -> _prev = _head;

		for (size_t i = 0; i < n; i ++ )
		{
			push_back(val);
		}
	}
	list (list<T>& x)
		:_size(0)
	{
		_head = new Node;
		_head -> _next = _head;
		_head -> _prev = _head;

		iterator it = x.begin();
		while (it != x.end())
		{
			push_back(*it);
			it ++ ;
		}
	}
	list (iterator first, iterator last)
		:_size(0)
	{
		_head = new Node;
		_head -> _next = _head;
		_head -> _prev = _head;
		iterator it = first;
		while (it != last)
		{
			insert(end(), *it);
			it ++ ;
		}
	}
	~list()
	{
		clear();
		delete _head;
		_head = nullptr;
	}
	// 访问
	// const版本的迭代器,迭代器的指向的内容不能被修改
	// 1、自己单独实现一个const版本的迭代器
	// 2、将const和非const合成一个,通过模板参数进行控制
	const_iterator begin() const
	{
		return _head->_next;
	}
	const_iterator end() const
	{
		return _head;
	}
	iterator begin()
	{
		return iterator(_head->_next);
	}
	iterator end()
	{
		return iterator(_head);
	}
	// list capacity
	bool empty()
	{
		return _size == 0;
	}
	size_t size()
	{
		return _size;
	}
	// list element access
	T& front()
	{
		return *begin();
	}
	T& back()
	{
		return *end();
	}
	// list modifiers
	/*void push_back(const T& val)
	{
	Node* tmp = new Node;
	tmp -> val = val;

	Node* tail = _head -> _prev;
	tmp->_next = tail->_next;
	tail->_next = tmp;
	tmp->_prev = tail;
	_head->_prev = tmp;

	_size ++ ;
	}*/
	void push_back(const T& val)
	{
		insert(end(), val);
	}
	void push_front(const T& val)
	{
		insert(begin(), val);
	}
	iterator insert (iterator position, const T& val)
	{
		Node* tmp = new Node(val);
		tmp->_next = position._node;
		tmp->_prev = position._node->_prev;
		position._node->_prev->_next = tmp;
		position._node->_prev = tmp;

		_size ++ ;
		return iterator(tmp);
	}
	void pop_back()
	{
		erase( -- end());
	}
	void pop_front()
	{
		erase(begin());
	}
	iterator erase (iterator position)
	{
		iterator tmp(position._node->_next);
		position._node->_prev->_next = position._node->_next;
		position._node->_next->_prev = position._node->_prev;
		delete position._node;

		_size -- ;

		return tmp;
	}
	void clear()
	{
		while (_size)
		{
			erase(begin());
		}
	}
	void swap(list& l)
	{
		std::swap(_head, l._head);
		std::swap(_size, l._size);
	}

private:
	Node* _head;
	size_t _size;
};

三、反向迭代器

通过前面例子知道,反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。

四、问题

1、迭代器中的箭头操作符为什么返回的是地址?

 答:其实是编译器省略了一个箭头,例如:Iterator it;

正常的调用是:it.operator->()->val; 省略了一个箭头是为了提高代码的可读性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1.使用uniapp搭建微信小程序项目并引入前端组件资源

文章目录 1. 项目配置1.1. 新建vue3项目1.2. 关联云空间1.3. 运行到微信开发者工具 2. 前端组件2.1. uniCloud的内置组件和扩展组件2.2. uView3.02.3. 在uniapp项目引入uview3 1. 项目配置 1.1. 新建vue3项目 由于我们要使用vue3而不是vue2&#xff0c;所以要选好版本&#x…

1688数据分析实操技巧||1688商品数据采集接口 数据分析

今天&#xff0c;聊一聊B2B平台的数据分析&#xff0c;以1688国内站为例。 1688平台数据接口 1688也属于阿里巴巴的体系&#xff0c;跟淘宝天猫运营很像&#xff0c;因此很多淘宝天猫的玩法调整后也适用于1688。数据分析也是如此。 在1688搞数据分析&#xff0c;搞数据化运营可…

路由策略与路由控制

1.路由控制工具 匹配工具1&#xff1a;访问控制列表 &#xff08;1&#xff09;通配符 当进行IP地址匹配的时候&#xff0c;后面会跟着32位掩码位&#xff0c;这32位称为通配符。 通配符&#xff0c;也是点分十进制格式&#xff0c;换算成二进制后&#xff0c;“0”表示“匹配…

(二刷)代码随想录第1天|704. 二分查找 27. 移除元素

704. 二分查找 704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode&#xff1a;704. 二分查找_哔哩哔哩_bilibili 给定一个 n 个元素有序的&#xff08;升序&#xff09…

(六)JSP教程——out对象

out对象是在JSP中经常使用到的对象&#xff0c;它本质上是一个输出流&#xff0c;前面已经多次使用&#xff0c;我们经常使用它的print()和println()方法&#xff0c;这些方法主要用于实现客户端数据的输出。通过out对象也可以直接向客户端发送一个由程序动态生成的HTML文件。 …

时序图详解

1.这是iic总线在回应时候的时序图&#xff0c;data in代表eeprom收到数据&#xff0c;回stm32的ack&#xff0c;数据回应&#xff0c;data out代表stm32收到eeprom的消息&#xff0c;数据输出ack回应 2.交叉线 代表在这一次输出高电平&#xff0c;或者在这一次也可能输出低电…

JAVA队列相关习题4

1. 用队列实现栈。 225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09; 一个队列无法实现栈 尝试使用两个队列 1)push元素的时候应当放在那里&#xff1f;哪个队列不为空就放在哪里 2&#xff09;出栈的时候&#xff0c;出不为空的队列size-1元素&#xff0c;剩余元…

学QT的第三天~

ikun登录界面完善 #include "mywidget.h" void MyWidget::bth1() { if(edit3 ->text()"520cxk"&&edit4 ->text()"1314520") { //1.实例化一个QmessageBox类的对象 QMessageBox box(QMessageBox::Information, //图标 "恭喜…

文字转语音软件下载教程

文字转语音软件下载教程 一&#xff0c;Whisper下载二&#xff0c;ggml-medium语言模型下载三&#xff0c;导入模型下载四&#xff0c;使用方法 一&#xff0c;Whisper下载 网址&#xff1a;https://bittly.cc/uL9xs 下拉选择&#xff1a; 进入下载页面&#xff0c;下载Whis…

分享一些跟客户降价时候可以用的方法

这几天碰到一个沙特的客户&#xff0c;一开始发了一个别人的设计图来问价格。因为产品都是根据图纸定制的&#xff0c;我就问他是否确定了场地&#xff0c;有没有详细的场地尺寸&#xff0c;客户说有&#xff0c;稍后就给。 过了一天&#xff0c;他就给了一个超大的尺寸&#x…

图像处理之SVD检测显示屏缺陷(C++)

图像处理之SVD检测显示屏缺陷&#xff08;C&#xff09; 文章目录 图像处理之SVD检测显示屏缺陷&#xff08;C&#xff09;前言一、SVD算法简介二、代码实现总结 前言 显示屏缺陷检测是机器视觉领域的一处较广泛的应用场景&#xff0c;显示屏主要有LCD和OLED&#xff0c;缺陷类…

爬虫:爬取豆瓣电影

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 上篇我们将到如何利用xpath的规则&#xff0c;那么这一次&#xff0c;我们将通过案例来告诉读者如何使用Xpath来定位到我们需要的数据&#xff0c;就算你不懂H5代码是怎么个嵌套或者十分复…

cesium 雷达遮罩(电弧球效果)

cesium 雷达遮罩(电弧球效果) 以下为源码直接复制可用 1、实现思路 通过修改“material”材质来实现轨迹球效果 2、代码示例 2.1 index.html <!DOCTYPE html> <html lang="en"><head><!

Python | Leetcode Python题解之第70题爬楼梯

题目&#xff1a; 题解&#xff1a; class Solution:def climbStairs(self, n: int) -> int:a, b 1, 1for _ in range(n - 1):a, b b, a breturn b

C#winfrom三层架构实现简单课程管理系统管理系统,三层架构实现增删改查

1. 项目展示 1.1登录展示 1.2添加课程信息展示 1.3课程信息管理-查询-修改-删除 1.4修改登录密码 2.项目功能介绍&#xff08;图&#xff09; 3.数据库设计 3.1 教师表设计 3.2 课程分类表 3.3 课程信息表 4. 创建样式界面 winfrom 超详细UI创建过程 实现双色球选号器UI界面…

在国企分公司做信息宣传新闻投稿的经验分享

作为一名国企分公司的信息宣传工作者,我亲历了从传统投稿方式到数字化转型的全过程,这段经历既充满了挑战,也收获了成长。回首最初的日子,那些用邮箱投稿的时光,至今仍让我感慨万千。 初尝辛酸,邮箱投稿的艰难岁月 刚接手信息宣传工作时,我满腔热情,却很快被现实的冷水浇了个透…

Blender材质,纹理,UV

1.材质Material&#xff0c;用于描述物体的表面性质&#xff0c;包含以下基本属性 -基础色 -金属/非金属 -粗糙度 -透光度 -凹凸细节 添加材质步骤&#xff1a; 1&#xff09;切换到材质预览模式 2&#xff09;打开材质面板 3&#xff09;添加一个材质&#xff0c;包括材…

node.js对数据库mysql的连接与操作(增、删、改、查、五种SQL语法)

前提&#xff1a;先在vscode终端下载安装mysql&#xff1a;npm install mysql -save 步骤总结&#xff1a; (1)建立与数据库的连接 (2)做出请求&#xff1a; 实际上就是操作mysql里的数据。增删改查 insert、delete、updata、select (3)通过回调函数获取结果 一、什么是SQ…

spring高级篇(七)

1、异常处理 在DispatcherServlet中&#xff0c;doDispatch(HttpServletRequest request, HttpServletResponse response) 方法用于进行任务处理&#xff1a; 在捕获到异常后没有立刻进行处理&#xff0c;而是先用一个局部变量dispatchException进行记录&#xff0c;然后统一由…

ssm+vue的私人健身和教练预约管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的私人健身和教练预约管理系统(有报告)。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通…
最新文章