list【2】模拟实现(含迭代器实现超详解哦)

这篇具有很好参考价值的文章主要介绍了list【2】模拟实现(含迭代器实现超详解哦)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言(实现概述)

在前面,我们介绍了list的使用:
戳我看list的介绍与使用详解哦

在本篇文章中将重点介绍list的接口实现,通过模拟实现可以更深入的理解与使用list
list【2】模拟实现(含迭代器实现超详解哦),C++初阶,list,c++,数据结构,stl
我们模拟实现的 list 底层是一个带头双向循环链表

在实现list时,我们首先需要一个结构体以表示链表中结点的结构list_node,大致包括数据与指向前后结点的指针

template<class T>
struct list_node  //结点类
{
	list_node<T>* _prev;
	list_node<T>* _next;
	T _date;

	list_node(const T& date = T()) //匿名对象
		: _prev(nullptr)
		, _next(nullptr)
		, _date(date)
	{}
};

在有了结点之后,还需要一个 list类,包括双向链表的头结点指针_pHead,链表中的元素个数_size

template<class T>
class list  //带头双向循环链表
{
	typedef list_node<T> Node;
private:
	Node* _pHead;
	size_t _size;
};

大致结构如下:
list【2】模拟实现(含迭代器实现超详解哦),C++初阶,list,c++,数据结构,stl
关于带头双向循环链表的实现可以参考之前的C语言版本实现,在本篇文章中结构将不是最重点的内容:戳我看C语言实现带头双向循环链表详解哦

与vector相同,list是一个类模板,其声明与定义不能分离。我们将模拟实现的list放在我们创建的命名空间内,以防止与库发生命名冲突。
在list的模拟实现中,我们只实现一些主要的接口,包括默认成员函数、迭代器、容量、元素访问与数据修改

list迭代器实现

与vector不同,list的迭代器是指针的封装,通过运算符重载来实现原生指针的功能
我们可以通过封装结点的指针,即list_node<T>*,来实现迭代器:

默认成员函数

对于默认成员函数,其实我们只需要实现构造函数即可,这个__list_iterator类的属性只有一个结构体指针,并不存在类中申请的资源,所以编译器生成的析构函数与赋值运算符重载就够用了,不需要再实现了。

  1. 默认构造
    对于默认构造函数,我们可以使用缺省参数,即参数类型为结构体指针,缺省值为nullptr
    直接在初始化列表中用参数初始化类属性即可:
	__list_iterator(Node* pNode = nullptr)
		:_pNode(pNode)
	{}
  1. 拷贝构造
    对于拷贝构造,参数必须是类类型的引用,可以加上const修饰(我们可以在类中将类类型__list_iterator<T, Ref, Ptr>重命名为self,以方便书写)
    在函数中直接赋值即可:
	__list_iterator(const self& it)
	{
		_pNode = it._pNode;
	}

operator* 与 operator->

迭代器使用时应该是与指针基本类似的,所以也需要重载*->

  1. 重载 *
    指针当然可以进行解引用的操作,指向容器中元素的指针。对这个指针进行解引用操作结果就应该是该指针指向的元素。对于list的迭代器而言,解引用该迭代器的结果就应该是结点中的_data元素的引用,类型为&T
    (我们可以为模板参数加上一个参数,即Ref,它表示T&
	Ref operator*()
	{
		return _pNode->_date;
	}
  1. 重载->
    T是自定义类型时,其指针还可以通过->直接访问到T类型对象_data中的元素,起指针作用的迭代器自然也需要实现这个功能
    但是对于这个运算符重载而言,它并不知道要返回T类型对象中的什么元素,所以这个operator->函数可以直接返回该迭代器对应的结点中的_data元素的指针,然后在调用的时候再通过->来访问其中元素:it->->a;(通过迭代器it访问T类型对象中的a元素)。
    但是,这样的形式访问又与指针的用法不一致,所以这里有一个特殊的规定,即规定需要使用it->a;的方式通过迭代器访问T类型对象中的元素,以获得与原生指针相同的使用方式
    (我们可以为模板参数加上一个参数,即Ptr,它表示T*
	Ptr operator->()
	{
		return &(_pNode->_date);
	}

operator++ 与 operator–

  1. 重载 ++
    ++操作即实现迭代器的指向向后移动一个元素,list的迭代器底层是一个结构体指针,所以只需要将当前_pNode->_next 赋值给_pNode即可
    ++分为前置++与后置++,在区别这两个的实现时,前面类和对象时已经详细介绍过了,即给后置++增加一个参数int,但是不传参,只用于区分前置与后置。
    另外后置++需要创建临时对象,在*this++后必须要返回临时对象而非引用:
	self& operator++()
	{
		_pNode = _pNode->_next;
		return *this;
	}
	self operator++(int)
	{
		self temp(*this);
		_pNode = _pNode->_next;
		return temp;
	}
  1. 重载 --
    重载--与前面的++类似,即_pNode->_prev 赋值给_pNode即可
	self& operator--()
	{
		_pNode = _pNode->_prev;
		return *this;
	}
	self operator--(int)
	{
		self temp(*this);
		_pNode = _pNode->_prev;
		return temp;
	}

operator== 与 operator!=

对于==!= 重载,即判断两个迭代器对象的属性是否相等即可

	bool operator==(const self& it)
	{
		return _pNode == it._pNode;
	}
	bool operator!=(const self& it)
	{
		return _pNode != it._pNode;
	}

迭代器实现概览

	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;

		Node* _pNode;

		__list_iterator(Node* pNode = nullptr)
			:_pNode(pNode)
		{}
		__list_iterator(const self& it)
		{
			_pNode = it._pNode;
		}


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


		self& operator++()
		{
			_pNode = _pNode->_next;
			return *this;
		}
		self operator++(int)
		{
			self temp(*this);
			_pNode = _pNode->_next;
			return temp;
		}
		self& operator--()
		{
			_pNode = _pNode->_prev;
			return *this;
		}
		self operator--(int)
		{
			self temp(*this);
			_pNode = _pNode->_prev;
			return temp;
		}


		bool operator==(const self& it)
		{
			return _pNode == it._pNode;
		}
		bool operator!=(const self& it)
		{
			return _pNode != it._pNode;
		}
	};

list主要接口实现

在实现list之前,我们可以对一些较为麻烦的类型进行重命名以方便书写:

typedef list_node<T> Node;
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;

默认成员函数

构造函数

实现构造函数时,我们需要实现无参构造、n个指定元素构造、迭代器区间构造以及拷贝构造

无参构造
由于我们模拟实现的list底层为带头双向循环链表,所以在无参构造时虽然没有在list中放入元素,但是还使需要先放入一个空结点作为头节点
创建头节点的操作在任何构造函数中都要先进行,所以我们将其封装为一个init_empty_list函数。这个初始化空list的函数需要new一个结点,然后使节点中的_prev_next都指向它自身,最后将_size赋值为0:

	void init_empty_list()
	{			
		_pHead = new Node();
		_pHead->_prev = _pHead;
		_pHead->_next = _pHead;
		_size = 0;
	}
	
	list()
	{
		init_empty_list();
	}

n个指定元素构造:
使用n个指定元素构造有两个参数,第一个就是int,第二个是const T&,缺省值为T()
函数中,首先调用init_empty_list构建一个头结点;
再循环,使用push_bake尾插n个指定元素value即可(push_back后面会实现):

	list(int n, const T& value = T())
	{
		init_empty_list();
		while (n--)
		{
			push_back(value);
		}
	}

迭代器区间构造
是用迭代器区间构造函数是一个函数模板,可以使用任何容器的迭代器区间来构造list
函数中,首先调用init_empty_list构建一个头结点;
然后再循环,使用push_bake尾插first迭代器的解引用出的元素,当firstlast相等时出循环:

	template <class Iterator>
	list(Iterator first, Iterator last)
	{
		init_empty_list();
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}

拷贝构造:
拷贝构造函数的参数是一个const list<T>&
实现时,首先调用init_empty_list构建一个头结点;
然后范围for,使用push_bake将l中的元素逐一尾插到list中:

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

析构函数

析构函数需要实现释放list中的资源。
首先复用clear,清空list中的元素。clear中会实现释放结点中的资源,后面部分会实现;
delete _pHead;,释放头节点中的资源,它会调用结点结构体的析构函数

	~list()
	{
		clear();
		delete _pHead;
	}

赋值重载

对于赋值运算符重载,我们直接使用新写法,即先使用参数l创建一个临时对象;
然后使用swap将临时对象与*this交换(后面会实现swap函数);
最后返回*this即可,创建的临时对象就会在函数栈帧销毁时自动释放

	list<T>& operator=(const list<T>& l)  //list& operator=(const list l) 对于赋值重载,这样也可
	{
		list<T> temp(l);
		swap(temp);
		return *this;
	}

迭代器

在前面已经实现了list的迭代器,它是结点指针的封装

这里暂时只实现beginend,关于反向迭代器的实现在后面会详细介绍。
begin返回首元素的地址,即头结点的下一个结点的地址
end返回尾元素下一个位置的地址,即头节点的地址,他们分别重载有const版本:

	iterator begin()
	{
		return iterator(_pHead->_next);
	}
	iterator end()
	{
		return iterator(_pHead);
	}
	
	const_iterator begin() const
	{
		return const_iterator(_pHead->_next);
	}
	const_iterator end() const
	{
		return const_iterator(_pHead);
	}

容量

在容器部分,由于list并没有容量的概念,所以我们只需要实现sizeempty即可;
list【2】模拟实现(含迭代器实现超详解哦),C++初阶,list,c++,数据结构,stl
我们在list的属性中,我们设置了_size,在插入元素时_size++,删除元素时_size--,所以这里只需要返回_size的值即可;
_size == 0时,list为空,empty返回true,否者返回false

	size_t size() const
	{
		return _size;
	}
	bool empty() const
	{
		if (_size == 0)
			return true;
		else
			return false;
	}

元素访问

由于list在任意位置访问元素的成本较高,就没有提供operator[]的接口,所以我们只需要实现frontback即可。分别返回首尾的元素,有普通对象与const对象两个重载版本:
list【2】模拟实现(含迭代器实现超详解哦),C++初阶,list,c++,数据结构,stl
在实现时,我们可以借助list的属性_pHead,即头结点的指针来访问首尾元素
我们模拟实现list的底层是带头双向循环链表,所以list中的第一个元素就是_pHead->_next指向的结点中的元素;list中的_pHead->_prev指向的结点中的元素

front只需要返回 _pHead->_next->_date 即可;
back返回_pHead->_prev->_date即可,返回值类型为T&,const版本就返回const T&即可:

	T& front()
	{
		return _pHead->_next->_date;
	}
	const T& front()const
	{
		return _pHead->_next->_date;
	}
	
	T& back()
	{
		return _pHead->_prev->_date;
	}
	const T& back()const
	{
		return _pHead->_prev->_date;
	}

数据修改

list【2】模拟实现(含迭代器实现超详解哦),C++初阶,list,c++,数据结构,stl

insert

list 的结构使在任意位置插入数据的效率是较高的,只需要创建结点,再链接到pos位置前即可

在实现insert时,首先new一个结点,类型为Node,并用val初始化(这个Node类型是前面重命名后的类型);
这时我们需要记录pos位置的结点指针为curpos位置前面的结点指针为prev,以方便后续链接;
然后将pos结点的前一个结点与新结点链接,即newnodeprev链接;
再将pos结点与新结点链接,即newnodecur链接;

最后,更新_size,并返回新结点的迭代器:

	// 在pos位置前插入值为val的节点
	iterator insert(iterator pos, const T& val)
	{
		Node* newnode = new Node(val);

		Node* cur = pos._pNode;
		Node* prev = cur->_prev;

		newnode->_prev = prev;
		prev->_next = newnode;

		newnode->_next = cur;
		cur->_prev = newnode;

		++_size;

		return iterator(newnode);
	}

erase

erase实现时,只需要释放pos位置的结点,并链接剩余的结点即可:

首先assert判断list是否为空;
这时我们需要记录pos位置的结点指针为curpos位置前面的结点指针为prevpos的后一个结点指针为next,以方便后续链接;
然后直接链接pos位置的前一个结点与后一个结点,即链接prevnext即可;

最后,释放cur指向的结点,更新_size,并返回next

	// 删除pos位置的节点,返回该节点的下一个位置
	iterator erase(iterator pos)
	{
		assert(!empty());
		Node* cur = pos._pNode;
		Node* prev = cur->_prev;
		Node* next = cur->_next;

		prev->_next = next;
		next->_prev = prev;

		delete cur;
		--_size;
		return iterator(next);
	}

push_back 与 push_front

对于头插与尾插的实现,复用insert即可:

push_front,即在首结点的前面一个位置插入一个元素,即begin()迭代器位置插入
push_back,即在尾结点的后一个位置插入一个元素,即end()位置插入

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

pop_back 与 pop_front

对于头删尾删的实现,复用erase即可

pop_front,即删除头节点,即 erase删除begin()位置的结点 即可;
pop_back,删除尾结点,即 erase删除end()前面一个结点即可,但是由于list迭代器不支持-操作,所以这里传参为--end()

	void pop_front()
	{
		erase(begin());
	}
	void pop_back()
	{
		erase(--end());
	}

clear

clear用于清理list中的所有元素,可以直接复用erase来实现清理

我们可以通过遍历迭代器的方式逐一释放结点:
it的初始值为begin(),循环逐一erase删除,当it等于end()的时候终止循环,就可以实现删除所有结点并保留头节点;
另外,由于erase删除某节点后,会返回删除节点的下一个位置,所以只要把返回值载赋值给it就实现了迭代器的向后移动

	void clear()
	{
		iterator it = begin();
		while (it != end())
		{
			it = erase(it);//erase返回删除的结点的下一个位置的迭代器
		}
	}

swap

实现list的交换函数时,只需要使用库swap交换list的属性即可,即交换_pHead_size

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

源码概览

(关于反向迭代器的实现在后面会详细介绍,现在可以暂时忽略)

#include<iostream>
#include<cassert>
#include"my_reverse_iterator.h"

namespace qqq
{
	template<class T>
	struct list_node
	{
		list_node<T>* _prev;
		list_node<T>* _next;
		T _date;

		list_node(const T& date = T()) //匿名对象
			: _prev(nullptr)
			, _next(nullptr)
			, _date(date)
		{}
	};

	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;

		Node* _pNode;

		__list_iterator(Node* pNode = nullptr)
			:_pNode(pNode)
		{}
		__list_iterator(const self& it)
		{
			_pNode = it._pNode;
		}


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


		self& operator++()
		{
			_pNode = _pNode->_next;
			return *this;
		}
		self operator++(int)
		{
			self temp(*this);
			_pNode = _pNode->_next;
			return temp;
		}
		self& operator--()
		{
			_pNode = _pNode->_prev;
			return *this;
		}
		self operator--(int)
		{
			self temp(*this);
			_pNode = _pNode->_prev;
			return temp;
		}


		bool operator==(const self& it)
		{
			return _pNode == it._pNode;
		}
		bool operator!=(const self& it)
		{
			return _pNode != it._pNode;
		}
	};

	template<class T>
	class list  //带头双向循环链表
	{
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;
		typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;

	public:
		/ constructor and destructor 
		void init_empty_list()
		{			
			_pHead = new Node();
			_pHead->_prev = _pHead;
			_pHead->_next = _pHead;

			_size = 0;
		}
		list()
		{
			init_empty_list();
		}
		list(int n, const T& value = T())
		{
			init_empty_list();

			while (n--)
			{
				push_back(value);
			}
		}
		template <class Iterator>
		list(Iterator first, Iterator last)
		{
			init_empty_list();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		list(const list<T>& l)
		{
			init_empty_list();
			for (auto el : l)
			{
				push_back(el);
			}
		}
		list<T>& operator=(const list<T>& l)  //list& operator=(const list l) 对于赋值重载,这样也可
		{
			list<T> temp(l);
			swap(temp);
			return *this;
		}
		~list()
		{
			clear();
			delete _pHead;
		}


		// List Iterator///
	
		iterator begin()
		{
			return iterator(_pHead->_next);
		}
		iterator end()
		{
			return iterator(_pHead);
		}
		const_iterator begin() const
		{
			return const_iterator(_pHead->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_pHead);
		}
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}


		/List Capacity//
		size_t size() const
		{
			return _size;
		}
		bool empty() const
		{
			if (_size == 0)
				return true;
			else
				return false;
		}

		///List Access///
		T& front()
		{
			return _pHead->_next->_date;
		}
		const T& front()const
		{
			return _pHead->_next->_date;
		}
		T& back()
		{
			return _pHead->_prev->_date;
		}
		const T& back()const
		{
			return _pHead->_prev->_date;
		}

		List Modify//
		void push_back(const T& val)
		{
			insert(end(), val);
		}
		void pop_back()
		{
			erase(--end());
		}
		void push_front(const T& val)
		{
			insert(begin(), val);
		}
		void pop_front()
		{
			erase(begin());
		}
		// 在pos位置前插入值为val的节点
		iterator insert(iterator pos, const T& val)
		{
			Node* newnode = new Node(val);

			Node* cur = pos._pNode;
			Node* prev = cur->_prev;

			newnode->_prev = prev;
			prev->_next = newnode;

			newnode->_next = cur;
			cur->_prev = newnode;

			++_size;

			return iterator(newnode);
		}
		// 删除pos位置的节点,返回该节点的下一个位置
		iterator erase(iterator pos)
		{
			assert(!empty());
			Node* cur = pos._pNode;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			prev->_next = next;
			next->_prev = prev;

			delete cur;
			--_size;
			return iterator(next);
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);//erase返回删除的结点的下一个位置的迭代器
			}
		}
		void swap(list<T>& l)
		{
			std::swap(_pHead, l._pHead);
			std::swap(_size, l._size);
		}

	private:
		Node* _pHead;
		size_t _size;
	};
};

总结

到此,关于list的模拟实现就到此结束了
模拟实现容器并不是为了造一个更好的轮子,而是为了更好的理解与使用容器

如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出

如果本文对你有帮助,希望一键三连哦

希望与大家共同进步哦文章来源地址https://www.toymoban.com/news/detail-694806.html

到了这里,关于list【2】模拟实现(含迭代器实现超详解哦)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • C++初阶—list深度解剖及模拟实现

      目录 ➡️0. 前言 😊1.简易框架实现 🐔1. list和__list_node分析实现 🐔2. 无参构造 😊2.迭代器实现 🐔1. list普通迭代器面临问题及解决方案 🐔2. __list_nodeiteratorlist三类分析 🐔3. list中const迭代器面临问题及解决方案 🐔4. list中模板参数为自定义类型迭代器优化 🐔5. list迭代

    2024年02月09日
    浏览(39)
  • 【C++初阶】list的模拟实现 附源码

    list底层是一个 双向带头循环链表 ,这个我们以前用C语言模拟实现过,-双向带头循环链表 下面是list的文档介绍: list文档介绍 我们会根据 list 的文档来模拟实现 list 的增删查改及其它接口。   既然是用C++模拟实现的,那么一定要 封装在类里 。 为了适合各种类型的数据,

    2024年02月17日
    浏览(42)
  • 【C++初阶】11. list的使用及模拟实现

    list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。 list与forward_list非常相似:最主要的不同在

    2024年02月12日
    浏览(42)
  • C++:模拟实现list及迭代器类模板优化方法

    本篇模拟实现简单的list和一些其他注意的点 如下所示是利用拷贝构造将一个链表中的数据挪动到另外一个链表中,构造两个相同的链表 lt作为形参,传引用可以提高传参的效率,同时应该加上const修饰来保证不会因为不小心修改了形参导致外部的实参也被修改,这样的结果是

    2024年02月13日
    浏览(40)
  • C++:关于模拟实现vector和list中迭代器模块的理解

    本篇是关于 vector 和 list 的模拟实现中,关于迭代器模块的更进一步理解,以及在前文的基础上增加对于反向迭代器的实现和库函数的对比等 本篇是写于前面模拟实现的一段时间后,重新回头看迭代器的实现,尤其是在模板角度对 list 中迭代器封装的部分进行解析,希望可以

    2024年02月07日
    浏览(45)
  • 【C++】反向迭代器的模拟实现通用(可运用于vector,string,list等模拟容器)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 我们要写出一个通用的反向迭代器模拟而且在保证代码简介不繁琐的的情况下,一定程度上使用我们自己模拟的已经封装好的iterator迭代器可以简化许多步骤,首先我们要知

    2024年02月14日
    浏览(56)
  • C++初阶之一篇文章教会你list(模拟实现)

    成员类型表 这个表中列出了C++标准库中list容器的一些成员类型定义。这些类型定义是为了使list能够与C++标准库的其他组件协同工作,并提供一些通用的标准接口。每个成员类型的用处: value_type : 这个成员类型代表list容器中存储的数据类型,即模板参数T的类型。 allocator_

    2024年02月12日
    浏览(40)
  • 『初阶数据结构 • C语言』⑫ - 堆的概念&&实现(图文详解+完整源码)

    目录 0.写在前面 1.什么是堆? 2.堆的实现 2.1 堆的结构定义 2.2 函数声明 2.3 函数实现 2.3.1 AdjustUp(向上调整算法) 2.3.2 AdjustDown(向下调整算法) 2.3.3 HeapCreate(如何建堆) 2.3.4 建堆的时间复杂度 3. 完整源码 Heap.h文件 Heap.c文件  Test.c文件  上一章中介绍了树和二叉树的概念

    2024年02月16日
    浏览(47)
  • 深入篇【C++】手搓模拟实现list类(详细剖析底层实现原理)&&模拟实现正反向迭代器【容器适配器模式】

    1.一个模板参数 在模拟实现list之前,我们要理解list中的迭代器是如何实现的。 在vector中迭代器可以看成一个指针,指向vector中的数据。它的解引用会访问到具体的数据本身,++会移动到下一个数据位置上去,这些都是因为vector具有天生的优势:空间上是连续的数组,这样指

    2024年02月15日
    浏览(46)
  • [STL-list]介绍、与vector的对比、模拟实现的迭代器问题

     list的底层是 带头双向链表 结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。 与其他的序列式容器相比(array,vector,deque),list通常 在任意位置进行插入、移除元素的执行效率更好 list最大的缺陷是 不支持任意位

    2024年04月15日
    浏览(96)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包