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 capacitybool empty(){return _size == 0;}size_t size(){return _size;}// list element accessT& 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.hqwc.cn/news/678909.html

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

相关文章

大数据毕业设计Python+Django旅游景点评论数据采集分析可视化系统 NLP情感分析 LDA主题分析 bayes分类 旅游爬虫 旅游景点评论爬虫 机器学习 深度学习 人工智能 计算机毕业设计

毕业论文&#xff08;设计&#xff09;开题报告 学生姓名 学 号 所在学院 信息工程学院 专 业 指导教师姓名 指导教师职称 工程师 助教 指导教师单位 论文&#xff08;设计&#xff09;题目 基于朴素贝叶斯算法旅游景点线上评价情感分析 开 题 报 告…

JavaEE技术之MySql高级-ShardingSphere5(SpringBoot版本:3.0.5)

文章目录 1 ShardingSphere-JDBC读写分离1.1 创建SpringBoot程序1.1.1、创建项目1.1.2、添加依赖1.1.3、创建实体类1.1.4、创建Mapper1.1.5、配置 Spring Boot1.1.6、配置shardingsphere 1.2 测试1.2.1 读写分离测试1.2.2 负载均衡测试1.2.3 事务测试常见错误 2 ShardingSphere…

JSP技术讲解

目录 1、JSP简介 2、JSP体验 3、JSP运行原理 4、JSP基本语法 5、JSP指令 6、JSP内置九大对象 7、JSP标签 8、JSP配置 9、JSP排错 10、总结 在前面的Servlet学习中发现Servlet本质是一个java程序&#xff0c;因此Servlet更加擅长编写程序的业务逻辑&#xff0c;而如果要…

数据结构学习——线性表、顺序表

1.线性表 线性表 &#xff08; linear list &#xff09; 是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一…

ICode国际青少年编程竞赛- Python-2级训练场-列表入门

ICode国际青少年编程竞赛- Python-2级训练场-列表入门 1、 Dev.step(3)2、 Flyer.step(1) Dev.step(-2)3、 Flyer.step(1) Spaceship.step(7)4、 Flyer.step(5) Dev.turnRight() Dev.step(5) Dev.turnLeft() Dev.step(3) Dev.turnLeft() Dev.step(7) Dev.turnLeft() Dev.…

pytest教程-41-钩子函数-pytest_runtest_teardown

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_runtest_call钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_runtest_teardown钩子函数的使用方法。 pytest_runtest_teardown 钩子函数在每个测试用例执行完成后被调用&…

数据结构学习——二叉树

1. 树概念及结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&…

【Docker学习】docker run的端口映射-p和-P选项

docker run的端口映射选项分为-p&#xff08;小写&#xff0c;全称--publish&#xff09;&#xff0c;-P&#xff08;大写&#xff0c;全称--publish-all&#xff09;&#xff0c;之前认为只有改变容器发布给宿主机的默认端口号才会进行-p的设置&#xff0c;而不改变默认端口号…

Java面试八股文(MySQL篇)

数据库三范式 数据库事务介绍 索引介绍 SQL优化手段 mysql union 与 union all 语法及用法 并发事务带来的问题 大表如何优化 索引类型介绍 MYSQL数据库锁介绍

leetcode91.解码方法(动态规划)

问题描述&#xff1a; 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; A -> "1" B -> "2" ... Z -> "26" 要 解码 已编码的消息&#xff0c;所有数字必须基于上述映射的方法&#xff0c;反向映射回字母&#xff08;可…

如何才能做好源代码防泄密

目前很多企业都拥有自己的研发机构&#xff0c;其研发成果往往体现在源代码和技术文档方面&#xff0c;这些核心机密&#xff0c;如何防止研发参与人员泄密&#xff0c;如何防止核心成员把研究成果带走另立山头&#xff0c;或者提供给竞争对手&#xff0c;是一个很现实的一个问…

Vue-路由介绍

目录 一、思考引入 二、路由介绍 一、思考引入 单页面应用程序&#xff0c;之所以开发效率高&#xff0c;性能高&#xff0c;用户体验好&#xff0c;是因为页面按需更新。 而如果要按需更新&#xff0c;首先需要明确&#xff1a;访问路径和组件的对应关系。该关系通过路由来…