【C++杂货铺】详解list容器

这篇具有很好参考价值的文章主要介绍了【C++杂货铺】详解list容器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list


目录

🌈前言🌈

📁 介绍

📁 使用

 📂 构造

 📂 迭代器iterator

 📂 capacity

 📂 modifiers

 📂 迭代器失效

📁 模拟实现

 📂 迭代器的实现

📂 代码展示

📁 和vector的区别

📁 总结


🌈前言🌈

        欢迎收看本期【C++杂货铺】,本期内容将讲解STL中关于list的内容,会分为一下几个方面进行讲解:第一,什么是list,和其他容器的比较;第二,list的常用接口的介绍;第三,从底层除法,模拟实现简易版list;最后,对比和vecotr的主要区别。

        以上就是本期要讲解的全部内容了,讲解之前需要你有数据结构中链表的储备知识,是为了更好的理解讲解内容。此外,模拟实现需要类和对象,模板等储备知识,如果只是想简单使用可以只看前两章。

        如果你还没有类和对象及模板的知识,可以阅览下面这几篇文章:【C++杂货铺】详解类和对象 [上]-CSDN博客

【C++杂货铺】详解类和对象 [中]-CSDN博客

【C++杂货铺】详解类和对象 [下]-CSDN博客

【C++杂货铺】模板-CSDN博客

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list

📁 介绍

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

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

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

        与之相对的,list的最大缺陷是不支持在任意位置的随机访问。

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list

📁 使用

        list接口较多,这里简单介绍一些常用的重要接口。

        下面是官方文档的链接,对于容器的学习还是要多看文档的。

        list - C++ Reference (cplusplus.com)

 📂 构造

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list

 📂 迭代器iterator

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list

 📂 capacity

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list

 📂 modifiers

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list

 📂 迭代器失效

        迭代器失效即迭代器所指向的节点无效,即该节点被删除。因为list底层是带头结点的双向循环链表,因此在list中进行插入时是不会导致迭代器失效的,只有在删除时才会失效,并且失效只是指向所删除结点的迭代器,其他迭代器不会受到影响

void TestListIterator1()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 list<int> l(array, array+sizeof(array)/sizeof(array[0]));
 auto it = l.begin();
 while (it != l.end())
 {
 // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值
 l.erase(it); 
 ++it;
 }
}

// 改正
void TestListIterator()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 list<int> l(array, array+sizeof(array)/sizeof(array[0]));
 auto it = l.begin();
 while (it != l.end())
 {
 l.erase(it++); // it = l.erase(it);
 }
}

📁 模拟实现

        对于list的模拟实现最难实现的就是迭代器的实现。所以下面将重点讲解迭代器内容。

 📂 迭代器的实现

        迭代器就是通过模拟指针,提供一种统一的方法来使用容器。

        对于vecotr这样的容器,迭代器可以直接是指针,但对于list这样的容器,不能直接使用原生指针,因为底层内存地址不是连续的。

        指针++,并不能实现node = node->next这样的操作。这里就要用到C++的重要组成部分了,运算符重载和实现了类。通过将指针封装成类,来实现运算符重载。

        这里迭代器使用三个模板参数,第一个表示数据data的类型,第二表示数据data的引用,第三个表示数据data的地址。

	template<class T,class Ref,class Ptr>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T,Ref,Ptr> iterator;

		//构造函数

		ListIterator(Node* node)
			:_node(node)
		{}

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

		Ptr operator->()
		{
			return &_node->data;
		}

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

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

		//--it
		iterator& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		iterator operator--(int)
		{
			iterator temp(*this);
			_node = _node->_prev;
			return temp;
		}

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

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

		Node* _node;
	};

📂 代码展示

        下面将list的实现,放在exercise命名空间中。

namespace exercise
{
	//节点类
	template<class T>
	struct ListNode
	{
		typedef ListNode<T> Node;
		Node* _next;
		Node* _prev;
		T data;

		ListNode(const T& val = T())
			:_next(nullptr)
			,_prev(nullptr)
			,data(val)
		{}


	};

	template<class T,class Ref,class Ptr>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T,Ref,Ptr> iterator;

		//构造函数

		ListIterator(Node* node)
			:_node(node)
		{}

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

		Ptr operator->()
		{
			return &_node->data;
		}

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

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

		//--it
		iterator& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		iterator operator--(int)
		{
			iterator temp(*this);
			_node = _node->_prev;
			return temp;
		}

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

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

		Node* _node;
	};

	//list类
	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;

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}

		list()
		{
			empty_init();
		}

		list(const list<T>& l)
		{
			empty_init();
			for (auto& e : l)
			{
				push_back(e);
			}
		}

		void swap(list<T>& temp)
		{
			std::swap(_head,temp._head);
			std::swap(_size, temp._size);
		}

		list<T>& operator=(list<T> temp) 
		{
			swap(temp);
			return *this;
		}

		void clear()
		{
			iterator it = _head->_next;
			while (it != _head)
			{
				it = erase(it);
			}
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
			_size = 0;
		}



		iterator begin()
		{
			return _head->_next;
		}

		iterator end()
		{
			return _head;
		}

		const_iterator begin() const
		{
			return _head->_next;
		}

		const_iterator end() const
		{
			return _head;
		}

		/*void push_back(const T& val)
		{
			Node* newnode = new Node(val);
			Node* tail = _head->_prev;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;
			tail->_next = newnode;
		}*/

		void push_back(const T& val)
		{
			insert(end(), val);
		}

		void insert(iterator pos, const T& val)
		{
			Node* newnode = new Node(val);
			Node* prev = pos._node->_prev;
			Node* next = pos._node;
			newnode->_prev = prev;
			prev->_next = newnode;
			newnode->_next = next;
			next->_prev = newnode;
			_size++;
		}

		iterator erase(iterator pos)
		{
			Node* prev = pos._node->_prev;
			Node* next = pos._node->_next;
			delete pos._node;
			prev->_next = next;
			next->_prev = prev;
			_size--;
			return next;
		}
		
		void pop_back()
		{
			erase(--end());
		}

		size_t size()
		{
			return _size;
		}


	private:
		Node* _head;
		size_t _size;
	};

}

📁 和vector的区别

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list

📁 总结

        以上,就是本期【C++杂货铺】的主要内容了,包含了list的介绍,list常用接口以及模拟实现list。

        如果感觉本期内容有帮助到你,欢迎点赞,收藏,关注Thanks♪(・ω・)ノ

【C++杂货铺】详解list容器,数据结构,C++杂货铺,c++,开发语言,学习,STL,数据结构,list文章来源地址https://www.toymoban.com/news/detail-851024.html

到了这里,关于【C++杂货铺】详解list容器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++杂货铺】引用

    前言:  相信大家在学习C语言的时候,最头疼的就是指针,经常会碰到一级指针、二级指针,这些指针使用起来,稍有不慎就会等导致程序崩溃,为了让广大程序员少掉点头发,C++中提出了 引用 这一概念。当然,在C++的代码中,仍然可以兼容C语言的指针。  在语法上 引用

    2024年02月16日
    浏览(48)
  • 【C++杂货铺】内存管理

    从用途和存储的角度来看,在C/C++程序中有 局部数据、静态数据、全局数据、常量数据、动态申请的数据 五种主要的数据,各种数据的特点如下: 局部数据 :随用随创建,存储在栈区,作用域只在局部,生命周期在局部,出了作用域就销毁。 静态数据 :存储在数据段,作

    2024年02月16日
    浏览(42)
  • 【C++杂货铺】拷贝构造函数

    📖 定义 拷贝构造函数 是构造函数的一个重载 ,它的本质还是 构造函数 ,那就意味着,只有在创建对象的时候,编译器才会自动调用它,那他和普通的构造函数有什么区别呢? 拷贝构造函数,是创建对象的时候,用一个已存在的对象,去初始化待创建的对象 。简单来说,

    2024年02月16日
    浏览(52)
  • 【C++杂货铺】内管管理

    目录 🌈前言🌈 📁 C/C++中内存分布 📁 new 和 delete的使用 📁 new 和 delete的优点 📁 new 和 delete的原理  📂 operator new 和 operator delete函数  📂 内置类型  📂 自定义类型 📁 内存泄漏 📁 总结         欢迎收看本期【C++杂货铺】,本期内容讲解C++内存管理。包含了C++中内存

    2024年04月14日
    浏览(48)
  • 【C++杂货铺】缺省参数、函数重载

     缺省参数是 声明或定义函数时为函数的参数指定一个缺省值 。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。  上面代码在 fun 函数的形参部分给了缺省值10,这意味着在调用 fun 函数的时候可以传参,也可以不传参,如果传参了那形参

    2024年02月16日
    浏览(38)
  • 【C++杂货铺】运算符重载

    本文将以日期类为基础,去探寻运算符重载的特性与使用方法,下面先给出日期类的基础定义: 备注 :拷贝构造函数和析构函数,均可以不写,因为当前日期类的三个成员变量都是内置类型,没有动态申请空间,使用浅拷贝就可以。 📖 如何比较两个日期的大小? 现如今,

    2024年02月16日
    浏览(74)
  • 【C++杂货铺】C++介绍、命名空间、输入输出

     C语言是 结构化 和 模块化 的语言,适合处理 较小规模 的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机,20世纪80年代,计算机界提出了 OOP (object oriented programming: 面向对象 )思想,支持面向对象的程序设计语言应

    2024年02月16日
    浏览(42)
  • 【C++杂货铺】再谈类和对象

    在创建对象的时候,编译器通过调用构造函数,在构造函数体中,给对象中的各个成员变量一个合适的初值。 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化, 构造函数体中的语句只能将其称为赋初值,而不能称作初

    2024年02月16日
    浏览(40)
  • 【C++杂货铺】string使用指南

    2024年02月14日
    浏览(45)
  • 【C++杂货铺】初识类和对象

    📖 面向过程 C语言是 面向过程的 ,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。以洗衣服这件事为例,下图是C语言完成洗衣服这件事的过程。 📖 面向对象 C++是 基于面向对象的 ,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完

    2024年02月16日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包