C++:List的使用和模拟实现

这篇具有很好参考价值的文章主要介绍了C++:List的使用和模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

                                                        创作不易,感谢三连!!

一、List的介绍

list的文档介绍

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

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

3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。

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

5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

要注意的是,list开始就不支持下标访问了,所以要访问都要以迭代器为准

void Print(const list<int>& l)
{
	//迭代去区间遍历
	list<int>::const_iterator it = l.begin();
	while (it != l.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	//范围for遍历
	for (auto e : l)
		cout << e << " ";
	cout << endl;
}

二、List的使用注意事项 

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

博主觉得跟之前vector的基本上差不了多少,如果不会看文档用库里面的list的可以去看博主只管关于string和vector的使用。

C++:String类的使用-CSDN博客 

C++:Vector的使用-CSDN博客

下面直接介绍List使用中的易错点

2.1 List的迭代器失效问题

        我们之前学习vector的时候,知道了insert和erase都有可能存在迭代器失效的问题,那list会出现这种情况吗??下面来进行分析

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

insert插入新节点的迭代器,因此insert不可能会出现失效的问题。

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

   而earse必然会失效,因为该迭代器对应的节点被删除了。如果我们想继续用的话,就得利用返回值去更新迭代器,返回值是被删除元素的下一个位置的迭代器。

2.2 List中sort的效率测试

我们用一段代码来测试一下list中sort的性能

void test_op()
{
	srand((unsigned int)time(NULL));
	const int N = 1000000;
	vector<int> v;
	v.reserve(N);
	list<int> lt1;
	list<int> lt2;
	for (int i = 0; i < N; ++i)
	{
		int e = rand();
		lt1.push_back(e);
		lt2.push_back(e);
	}
	// 拷贝到vector排序,排完以后再拷贝回来
	int begin1 = clock();
	for (auto e : lt1)
	{
		v.push_back(e);
	}
	sort(v.begin(), v.end());
	size_t i = 0;
	for (auto& e : lt1)
	{
		e = v[i++];
	}
	int end1 = clock();
	//list调用自己的sort
	int begin2 = clock();
	lt2.sort();
	int end2 = clock();
	printf("vector sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记 会发现哪怕我先拷贝到vector排完再拷贝回去效率都比list的sort效率高,所以list的sort实际中意义不是很大!!

 三、模拟实现的注意事项

     还是跟之前模拟实现一样,先看看SGI版本的源码 ,list本质上是带头双向链表

第一部分    链表节点

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

第二部分   迭代器

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

第三部分、链表

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

这里我们可以先实现链表节点结构体 这里用sturct把权限放开。

//节点的封装
template<class T>
struct list_node
{
	list_node<T>* _prev;
	list_node<T>* _next;
	T _data;

	//节点的构造函数
	list_node(const T& val = T())
		:_prev(nullptr)
		, _next(nullptr)
		, _data(val)
	{}
};

然后封装一个链表,将头结点作为自己的成员变量封装起来

	template<class T>
class list
{
	typedef list_node<T>  node;//typedef可以帮助我们简洁代码
	private:
		node* _head;
	};

下面开始进行我们的重中之重——迭代器 

四、正向迭代器的实现

2.1 正向迭代器的封装

      在学习Vector的时候,我们发现其实vector的迭代器就是一个原生指针,所以我们将他改了名字

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

      这得益于vector空间连续的特点,所以对指针进行加和减再进行解引用可以访问到我们想要的元素,但是链表可以吗?

 C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

     虽然看似我们好像用箭头连接起来了,但其实他们空间上是不连续的,那我们对一个节点指针进行加减,就很难说能不能找到下一个节点,更多的是找不到的情况

    那我们思考一样,如果我们要搞一个迭代器,我们希望怎么去得到我们的数据呢??我们希望我们解引用的时候,可以拿到他的data,希望++的时候,可以拿到他的next,--的时候,可以拿到他的prev。  那我们怎么去改变原生操作符的行为呢?答案就是运算符重载!所以我们可以将迭代器单独封装成一个类去管理节点,改变运算符的行为!!

       我们先进行实现,然后再慢慢分析

	//封装迭代器
	template<class T, class Ref, class Ptr>//Ref用于引用是否const,Ptr用于指针是否const
	struct list_iterator
	{
		typedef list_node<T> node;
		typedef list_iterator<T, Ref, Ptr>  self;
		node* _node;

		//迭代器的构造函数
		list_iterator(node* n)//迭代器的构造
			:_node(n)
		{}
		//实现*
		Ref operator*() const
		{
			return _node->_data;
		}
		//实现->
		Ptr operator->() const
		{
			return &operator*();    //本来是两个->,为了增强可读性,我们封装了这个函数 比如当我们存储的结构体解引用后有多个成员,那么我们可以通过箭头的直线去找到对应我们想要的成员	
		}
		//前置++
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//后置++
		self operator++(int)
		{
			self temp(*this);
			++*this;
			return temp;
		}
		//前置--
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		//后置--
		self operator--(int)
		{
			self temp(*this);
			--*this;
			return temp;
		}
		//!=
		bool operator!=(const self& s) const
		{
			return _node != s._node;
		}
		//==
		bool operator==(const self& s) const
		{
			return _node == s._node;
		}
	};

第一个模版参数是类型,第二个模版参数是引用,第三个模版参数是指针

       Ref和Ptr是用来区分正常的迭代器和const修饰的迭代器,Ref是T&或者是const T&,这样可以在某些时候我们去限制data不能被修改。而Ptr是T*或者是const T*,重载箭头的作用是如果我们data存储的是一个自定义类型,这个时候如果直接解引用肯定是不行的,所以我们的箭头可以在解引用的时候先返回data的地址,然后我们就可以通过箭头去访问他不同的成员变量

下面举个data存的是自定义类型的例子

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

2.2 迭代器的使用

template<class T>
class list
{
	typedef list_node<T>  node;//typedef可以帮助我们简洁代码
public:
	//正向迭代器
	typedef list_iterator<T, T&, T*>   iterator;
	typedef list_iterator<T, const T&, const T*>   const_iterator;
	//可读可写正向迭代器
	iterator begin()
	{
		return iterator(_head->_next);
	}
	iterator end()
	{
		return iterator(_head);
	}
	//可读不可写正向迭代器
	const_iterator begin() const
	{
		return const_iterator(_head->_next);
	}
	const_iterator end() const
	{
		return const_iterator(_head);
	}
	private:
		node* _head;
	};

这边我们用到了匿名对象。

思考:这里的const迭代器为什么不能直接用const修饰普通迭代器??

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

       因为typedef碰到const的话,就不是简单的字符串替换  实际上你以为的const T* ,在这里变成了T*const ,因为迭代器我们是希望他可以进行++和--的,而我们只是不希望他指向的内容给改变,所以我们的const要修饰的是指针的内容,而不是修饰指针。

五、list相关的成员函数

3.1  构造函数

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

1、默认构造函数

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

因为无论如何都要有哨兵节点,所以我们直接封装一个

	void empty_init()
	{
		_head = new node;
		_head->_next = _head;
		_head->_prev = _head;
	}

所以可以这么写

	//默认构造函数
	list()
	{
		empty_init();
	}

2、有参构造函数

//有参构造函数
list(size_t n, const T& val = T())
{
	empty_init();
	for (size_t i = n; i > 0; --i)
		push_back(val);
}

 3、迭代器区间构造函数

//迭代器区间构造函数
template <class InputIterator>
list(InputIterator first, InputIterator last)
{
	empty_init();
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

4、拷贝构造的传统写法

传统方法就是一个个拷贝过去

//拷贝构造函数传统写法
list(const list<T>& lt)
{
	empty_init();
	for (auto e : lt)
		push_back(e);
}

5、拷贝构造的现代写法+swap

      现代写法就是,我先创建一个临时对象让他利用被拷贝对象的迭代器构造出来,然后再交换,窃取革命成功,被利用完后的临时对象会在栈帧结束后被清除(典型的资本家思维)

	//交换函数
	void swap(list<T>& temp)
	{
		std::swap(_head, temp._head);
	}
	//拷贝构造函数的现代写法
	list(const list<T>& lt)
	{
		empty_init();
		list<T> temp(lt.begin(), lt.end());//复用迭代器区间构造,让别人构造好了,我再窃取革命成果
		swap(temp);
	}

3.2 clear和析构函数

    list不像vector一样,不能直接用头指针delete,因为空间不连续,所以要一个个节点去delete,所以在这之前,我们可以先实现clear,clear的作用是把链表清空,只剩一个头节点,然我们的析构函数再复用clear,然后再单独delete头节点就行了!!

	//clear 只留一个头节点
	void clear()
	{
		iterator it = begin();
		while (it != end())
			it = erase(it);
	}
	//析构函数
	~list()
	{
		clear();
		delete _head;
		_head = nullptr;
	}

3.3 赋值重载和assign

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

       assign和=的本质上都是,先将原来的空间的内容给清空,换成的内容。 只不过区别就是assign可以利用迭代器去控制被替换的范围,也可以自己去换成n个一样的元素。所以我们先实现assign,再实现=

1、assign直接替换

//assign(直接替换)
void assign(size_t n, const T& val)
{
	clear();
	for (size_t i = n; i > 0; --i)
		push_back(val);
}

2、assign迭代器区间替换

	//assign(迭代器区间替换)
	template <class InputIterator>
	void assign(InputIterator first, InputIterator last)
	{
		clear();
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}

3、assign直接替换重载(防止间接寻址)

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

思考:我们的本意是将lt2替换成5个2,我们发现我们调的竟然是迭代器区间构造的assign,为什么会这样呢?????     

      因为重载类型会优先找最匹配的,assign的第一个版本的n是size_t类型,我们传的整数默认是int所以会发生强制类型转化,而第二个版本恰好可以变成两个int,所以他会走迭代器区间版本。所以此时有两个方案,第一个方案是我们要在第一个参数后面加u,但是这不符合我们的使用习惯,所以我们可以采用第二个方案,写个重载版本。

//assign重载版本  防止间接寻址
void assign(int n, const T& val)
{
	clear();
	for (size_t i = n; i > 0; --i)
		push_back(val);
}

4、赋值重载传统写法 

直接复用assign

	// 赋值重载的传统写法
	list<T>& operator=(const list<T>& lt)
	{
		assign(lt.begin(), lt.end());
		return *this;
	}

5、赋值重载的现代写法

list<T>& operator=(list<T> lt)
{
	swap(lt);//利用值传递拷贝的临时对象进行交换
	return *this;
}

3.4 修改相关函数(Modifiers)

1、empty、size

//size
size_t size() const
{
	size_t n = 0;
	for (auto e : *this)
		++n;
	return n;
}
//empty
bool empty() const
{
	return node->next == node;
}

2、insert

我们先实现insert和erase,其他的就可以直接复用了

//insert
iterator insert(iterator pos, const T& val)
{
	node* cur = pos._node;//记录当前节点
	node* prev = cur->_prev;//记录前驱节点
	node* newnode = new node(val);//建立新节点
	//开始改变指向
	newnode->_next = cur;
	cur->_prev = newnode;
	prev->_next = newnode;
	newnode->_prev = prev;
	return iterator(newnode);
}

3、erase

//erase
iterator erase(iterator pos)
{
	assert(pos != end());//确保不是删除哨兵位置
	node* prev = pos._node->_prev;
	node* next = pos._node->_next;
	prev->_next = next;
	next->_prev = prev;
	delete pos._node;
	return iterator(next);//利用匿名对象返回
}

4、尾插尾删头插头删

//pushback 尾插
void push_back(const T& val)
{
	insert(end(), val);
}
//pushfront 头插
void push_front(const T& val)
{
	insert(begin(), val);
}
//popback 尾删
void pop_back()
{
	erase(--end());
}
//popfront 头删
void pop_front()
{
	erase(begin());
}

5、resize

//resize  如果n小于当前容量的大小,则内容将减少到前n个元素 当n大于容器大小时,则在末尾插入任意容量的内容。
void resize(size_t n, const T& val = T())
{
	size_t sz = size();//记录当前的有效元素的个数
	while (n < sz)
	{
		pop_back();
		--sz;
	}
	while (n > sz)
	{
		push_back(val);
		++sz;
	}
}

六、反向迭代器的实现

sgi版本下的反向迭代器,其实就是将构建一个反向迭代器的类将正向迭代器封装起来,这个时候正向迭代器的++就是反向迭代器的--

template<class iterator, class Ref, class Ptr>
struct list_reverse_iterator
{
	typedef list_reverse_iterator<iterator, Ref, Ptr> self;

	//用正向迭代器去构造反向迭代器
	list_reverse_iterator(iterator it)
		:_cur(it)
	{}
	//解引用
	Ref operator*() const
	{
		iterator temp = _cur;
		--temp;
		return *temp;
	}
	//实现->
	Ptr operator->() const
	{
		return &operator*();
	}
	//前置++
	self& operator++()
	{
		--_cur;
		return *this;
	}
	//后置++
	self operator++(int)
	{
		iterator temp(_cur);
		--*this;
		return temp;
	}
	//前置--
	self& operator--()
	{
		++_cur;
		return *this;
	}
	//后置--
	self operator--(int)
	{
		iterator temp(_cur);
		++*this;
		return temp;
	}
	//不等于
	bool operator!=(const self& s)
	{
		return _cur != s._cur;
	}
	//等于
	bool operator==(const self& s)
	{
		return _cur == s._cur;
	}
	iterator _cur;
};

思考:为什么解引用的是前一个位置的元素???

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

通过这个我们来看看vector下的反向迭代器代码:

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记

         复用性很高,和list的区别就是因为是随机迭代器,所以多了+和-的接口,第二个就是不需要->,所以其实模版也可少传一个 

 七、list模拟实现的全部代码

//c++喜欢ListNode驼峰法命名  为了和STL风格一致,我们也用小写
//但是STL版本和java喜欢小写带_  
namespace cyx
{
	//节点的封装
	template<class T>
	struct list_node
	{
		list_node<T>* _prev;
		list_node<T>* _next;
		T _data;

		//节点的构造函数
		list_node(const T& val = T())
			:_prev(nullptr)
			, _next(nullptr)
			, _data(val)
		{}
	};
	//封装迭代器
	template<class T, class Ref, class Ptr>//Ref用于
	struct list_iterator
	{
		typedef list_node<T> node;
		typedef list_iterator<T, Ref, Ptr>  self;
		node* _node;

		//迭代器的构造函数
		list_iterator(node* n)//迭代器的构造
			:_node(n)
		{}
		//实现*
		Ref operator*() const
		{
			return _node->_data;
		}
		//实现->
		Ptr operator->() const
		{
			return &operator*();    //本来是两个->,为了增强可读性,我们封装了这个函数 比如当我们存储的结构体解引用后有多个成员,那么我们可以通过箭头的直线去找到对应我们想要的成员	
		}
		//前置++
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//后置++
		self operator++(int)
		{
			self temp(*this);
			++*this;
			return temp;
		}
		//前置--
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		//后置--
		self operator--(int)
		{
			self temp(*this);
			--*this;
			return temp;
		}
		//!=
		bool operator!=(const self& s) const
		{
			return _node != s._node;
		}
		//==
		bool operator==(const self& s) const
		{
			return _node == s._node;
		}
	};
	template<class iterator, class Ref, class Ptr>
	struct list_reverse_iterator
	{
		typedef list_reverse_iterator<iterator, Ref, Ptr> self;

		//用正向迭代器去构造反向迭代器
		list_reverse_iterator(iterator it)
			:_cur(it)
		{}
		//解引用
		Ref operator*() const
		{
			iterator temp = _cur;
			--temp;
			return *temp;
		}
		//实现->
		Ptr operator->() const
		{
			return &operator*();
		}
		//前置++
		self& operator++()
		{
			--_cur;
			return *this;
		}
		//后置++
		self operator++(int)
		{
			iterator temp(_cur);
			--*this;
			return temp;
		}
		//前置--
		self& operator--()
		{
			++_cur;
			return *this;
		}
		//后置--
		self operator--(int)
		{
			iterator temp(_cur);
			++*this;
			return temp;
		}
		//不等于
		bool operator!=(const self& s)
		{
			return _cur != s._cur;
		}
		//等于
		bool operator==(const self& s)
		{
			return _cur == s._cur;
		}
		iterator _cur;
	};
	template<class T>
	class list
	{
		typedef list_node<T>  node;//typedef可以帮助我们简洁代码
	public:
		//正向迭代器
		typedef list_iterator<T, T&, T*>   iterator;
		typedef list_iterator<T, const T&, const T*>   const_iterator;
        //typedef __list_const_iterator<T> const_iterator;不行
		//反向迭代器
		typedef list_reverse_iterator<iterator, T&, T*>    reverse_iterator;
		typedef list_reverse_iterator<iterator, const T&, const T*>  const_reverse_iterator;
		//可读可写正向迭代器
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		//可读不可写正向迭代器
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}
        //可读可写的反向迭代器
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}
		//可读不可写的反向迭代器
		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}
		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}
		//默认构造函数
		list()
		{
			empty_init();
		}
		//有参构造函数
		list(size_t n, const T& val = T())
		{
		    empty_init();
			for (size_t i = n; i > 0; --i)
				push_back(val);
		}
		//迭代器区间构造函数
		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
		     empty_init();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		//拷贝构造函数传统写法
		/*list(const list<T>& lt)
		{
			empty_init();
			for (auto e : lt)
				push_back(e);
		}*/
		//交换函数
		void swap(list<T>& temp)
		{
			std::swap(_head, temp._head);
		}
		//拷贝构造函数的现代写法
		list(const list<T>& lt)
		{
			empty_init();
			list<T> temp(lt.begin(), lt.end());//复用迭代器区间构造,让别人构造好了,我再窃取革命成果
			swap(temp);
		}
		//assign(迭代器区间替换)
		template <class InputIterator>
		void assign(InputIterator first, InputIterator last)
		{
			clear();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		//assign(直接替换)
		void assign(size_t n, const T& val)
		{
			clear();
			for (size_t i = n; i > 0; --i)
				push_back(val);
		}
		//assign重载版本  防止间接寻址
		void assign(int n, const T& val)
		{
			clear();
			for (size_t i = n; i > 0; --i)
				push_back(val);
		}
		// 赋值重载的传统写法
		list<T>& operator=(const list<T>& lt)
		{
			assign(lt.begin(), lt.end());
			return *this;
		}
		// 赋值重载的现代写法
		//list<T>& operator=(list<T> lt)
		//{
		//	swap(lt);//利用值传递拷贝的临时对象进行交换
		//	return *this;
		//}
		//析构函数
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
		//size
		size_t size() const
		{
			size_t n = 0;
			for (auto e : *this)
				++n;
			return n;
		}
		//insert
		iterator insert(iterator pos, const T& val)
		{
			node* cur = pos._node;//记录当前节点
			node* prev = cur->_prev;//记录前驱节点
			node* newnode = new node(val);//建立新节点
			//开始改变指向
			newnode->_next = cur;
			cur->_prev = newnode;
			prev->_next = newnode;
			newnode->_prev = prev;
			return iterator(newnode);
		}
		//erase
		iterator erase(iterator pos)
		{
			assert(pos != end());//确保不是删除哨兵位置
			node* prev = pos._node->_prev;
			node* next = pos._node->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos._node;
			return iterator(next);//利用匿名对象返回
		}
		//pushback 尾插
		void push_back(const T& val)
		{
			insert(end(), val);
		}
		//pushfront 头插
		void push_front(const T& val)
		{
			insert(begin(), val);
		}
		//popback 尾删
		void pop_back()
		{
			erase(--end());
		}
		//popfront 头删
		void pop_front()
		{
			erase(begin());
		}
		//clear 只留一个头节点
		void clear()
		{
			iterator it = begin();
			while (it != end())
				it = erase(it);
		}
		//resize  如果n小于当前容量的大小,则内容将减少到前n个元素 当n大于容器大小时,则在末尾插入任意容量的内容。
		void resize(size_t n, const T& val = T())
		{
			size_t sz = size();//记录当前的有效元素的个数
			while (n < sz)
			{
				pop_back();
				--sz;
			}
			while (n > sz)
			{
				push_back(val);
				++sz;
			}
		}
		//empty
		bool empty() const
		{
			return node->next == node;
		}
	private:
		node* _head;
		//用来初始化  类内部自己用,设私有
		void empty_init()
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}
	};

    接口暂时就搞这些,如果后面有时间再写些比较复杂的接口,这一篇不太好理解,讲解不到位还请见谅

C++:List的使用和模拟实现,C++学习之路,c++,list,windows,开发语言,笔记文章来源地址https://www.toymoban.com/news/detail-843292.html

到了这里,关于C++:List的使用和模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【C++】list的使用与模拟实现

    目录 一、list介绍 二、list的使用  1、list的构造 2、list capacity 3、list element access 4、list iterator 5、list modifiers 5.1、insert 6、list Operations 6.1、sort 7、list的迭代器失效 三、list模拟实现 1、push_back 2、iterator 3、const iterator 4、Ptr 5、insert 及其复用 6、erase 及其复用 7、clear 8、构造函

    2023年04月26日
    浏览(38)
  • C++:List的使用和模拟实现

                                                            创作不易,感谢三连!! list的文档介绍 1. list是可以 在常数范围内在任意位置进行插入和删除的序列式容器 ,并且该容器 可以前后双向迭代。 2. list的 底层是双向链表结构, 双向链表中每个元素存储在互不相

    2024年03月25日
    浏览(38)
  • 【C++】list的使用和模拟实现

    list的底层是一个双向带头循环链表,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素,其遍历只能通过迭代器来实现,范围for的底层也是迭代器。 迭代器是所有容器都可以使用的迭代方式。 与list类似的还有forward_list,底

    2024年02月09日
    浏览(47)
  • 【C++干货铺】list的使用 | 模拟实现

    ========================================================================= 个人主页点击直达: 小白不是程序媛 C++专栏: C++干货铺 代码仓库: Gitee ========================================================================= 目录 list的介绍及使用 list的介绍 list的使用 list的构造 list迭代器的使用 list的增删查改

    2024年02月04日
    浏览(37)
  • [C++入门]---List的使用及模拟实现

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

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

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

    2024年02月12日
    浏览(41)
  • C++ STL之list的使用及模拟实现

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

    2024年01月24日
    浏览(68)
  • 【C++模拟实现】list的模拟实现

    作者:爱写代码的刚子 时间:2023.9.3 前言:本篇博客关于list的模拟实现和模拟实现中遇到的问题 list模拟实现的部分代码 list模拟实现中的要点 const_iterator的实现 我们选择使用模版参数,复用iterator的类,设置三个模版参数: templateclass T,class Ref,class Ptr 并且 typedef __list_iter

    2024年02月09日
    浏览(52)
  • C++ list 模拟实现

      目录 1. 基本结构的实现 2.  list() 3. void push_back(const T val) 4. 非 const 迭代器 4.1 基本结构  4.2 构造函数  4.3 T operator*() 4.4  __list_iterator operator++() 4.5 bool operator!=(const __list_iterator it) 4.6 T* operator-() 5. const 迭代器  6. begin()  end() ​编辑 7. iterator insert(iterator pos, const T v

    2024年02月08日
    浏览(47)
  • C++ list模拟实现

    源码中的list实现为 带头双向链表   list类的对象有两个成员:指向头结点的指针_head,统计数据个数的_size 在模拟实现list之前,需要先模拟实现 结点类,迭代器类 结点类:三个成员,_data _prev _next , 实现成struct (也是类,不过与class不同的是,它的成员都是公开的,都可以

    2024年02月11日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包