首页 > 编程语言 >C++——list的实现以及源码

C++——list的实现以及源码

时间:2024-05-26 17:29:30浏览次数:25  
标签:node head ListNode iterator list C++ next 源码 prev

前言:

最近学习了c++list的实现,这让我对迭代器的理解又上升了一个新的高度,注意:代码里的list是放在一个叫zgw的命名空间里边,但是在实现list的代码中没有加namespace,这里给个注意,以后复习时能看懂。

list的节点:

我们首先需要搞出一个list的节点,来存储数据,以及节点的下一个指针,和节点的上一个指针,STL库里边这样设计的,所以我们这样设计:

	template< class T>
	struct ListNode
	{
		struct ListNode<T>* _next; 
		struct ListNode<T>* _prev;
		T _data;
		ListNode(const T& data = T())   //这里给的是匿名对象
			:_next(nullptr),
			_prev(nullptr),
			_data(data) {};
	};

设计这个节点应该是没有什么难度的。
 

包装list类:
 

template<class T>
class list
{
	typedef ListNode<T> node;
public:
	list() :_head(new node())
	{
		_head->_next = _head;
		_head->_prev = _head;
	}
private:
	node* _head;
};

为了让我们的list更加具有可读性,我们将,ListNode<T>重命名为node。然后我们要给一个list的无参构造,相信到现在都能看得懂。

迭代器的设计:

前方高能!!!

然后就是上强度的地方,我们需要设计list的迭代器。我们先分析一下list指针与vector的指针又什么区别呢?

首先我们list存的是ListNode<T>节点的指针,每一个新的节点都是new出来的,而且是通过指针将他们链接起来,他在物理层面上就不是连续的。

所以当我们解引用就不是一个内置类型,或者是已经设计好的自定义类型,它就没有了重载运算符,因为我们的节点就是我们自己定义的自定义类型。就算是迭代器也必要支持重载运算符。

我们举一个例子
vector的例子,当我们要搞一个存储int数据的vector容器。

void Test4()
{
	vector<int> v1 = { 1,2,3,4 };
	vector<int>::iterator it1 = v1.begin();
	cout << *it1 << endl;
}

这里我们是存储int内置类型,当我们解引迭代器时,实际是解引用int类型的指针,然后也支持流插入,所以可以直接打印第一个元素。
 

我后我们再想我们如果要用vector存储一个我们自己搞的一个类型,是否还支持流插入呢?

class aa
{
	aa(int a=10,int b=20):
		_a(a),_b(b)
	{}
private:
	int _a;
	int _b;
};

void Test4()
{
	vector<aa> v1 ;
	aa a1;
	v1.push_back(a1);
	vector<aa>::iterator it1 = v1.begin();
	cout << *it1 << endl;
}

上面这个代码会不会报错呢?当然肯定会的,为什么呢?

就是因为我们没有重载流插入。

所以通过这个例子我们应该明白了,我们ListNode本生就是一个我们自己设计的类型,所以当我们在list返回ListNode指针再解引用时肯定是不行的,因为我们没有为ListNode设计重载运算符,但是我们在这有一个新的思路我们能不能再设计一个类,当做list的迭代器,这个类迭代器存ListNode类型的指针。

在第一次听到这个设计我也是很懵逼的,都是再通过我看了两遍教学课程,再加上自己研究了一个下午,终于是领悟了其中的原理,所以想好好理解还是得自己研究。

设计的源码:


namespace zgw
{
	//结构体定义
	template< class T>
	struct ListNode
	{
		struct ListNode<T>* _next;
		struct ListNode<T>* _prev;
		T _data;
		ListNode(const T& data = T())
			:_next(nullptr),
			_prev(nullptr),
			_data(data) {};
	};
		

	template <class T,class Ref,class Ptr>//我们设计三个参数的模板迭代器,以便我们返回对应的指针
	struct  ListIterator                  //和引用(在这里的我们需要设计const_iterator,以及
	{                                     //iterator两种类型的迭代器,然后我们再通过typedef
		typedef ListNode<T> node;         //封装一下,提高可读性
		typedef ListIterator<T,Ref,Ptr> Self;

		ListIterator(node*head) :
		_node(head)
		{};

		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}

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

		bool operator==(const Self&node)
		{
			return _node == node._node;
		}

		bool operator!=(const Self& node)
		{
			return _node != node._node;
		}
		
		node* _node;
	};



	//封装链表,这只是一个头节点,当我们返回begin(),和end()时,
    //我们其实返回的是一个ListNode<T>类型的指针
	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;
		list() :_head(new node())     //当我们需要什么类型的迭代器就传对应的typedef
		{
			_head->_next = _head;
			_head->_prev = _head;
		}

		const_iterator cbegin()
		{
			return const_iterator(_head->_next);
		}

		const_iterator cend()
		{
			return const_iterator(_head);
		}

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

		iterator end()
		{
			return iterator(_head);
		}

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

		iterator insert(iterator pos,const T&data)
		{	
			node* cur = pos._node;
			node* newnode = new node(data);
			node* prev = cur->_prev;
			newnode->_next = cur;
			prev->_next = newnode;
			newnode->_prev = prev;
			cur->_prev = newnode;
			return iterator(newnode);
		} 

		iterator erase(iterator pos)
		{
			assert(pos != end()._node);
			node* cur = pos._node;
			node* prev=cur->_prev;
			node* next = cur->_next;
			prev->_next = next;
			next->_prev = prev;
			delete cur;
			return iterator(next);
		}
		
		void pop_back()
		{
			assert(_head != begin()._node);
			node* tail= end()._node->_prev;
			node* _head = end()._node;
			tail->_prev->_next = _head;
			_head->_prev = tail->_prev;
			delete tail;
		}

		void pop_front()
		{
			erase(begin());
		}

		void push_front(const T&data)
		{
			insert(begin(), data);
		}

	private:
		node* _head;
	};
}

标签:node,head,ListNode,iterator,list,C++,next,源码,prev
From: https://blog.csdn.net/zgwnb666/article/details/139216230

相关文章

  • Vue3源码解析--收集的依赖是什么?怎么收集的?什么时候收集的?
    从Vue开始较大范围在前端应用开始,关于Vue一些基础知识的讨论和面试问题就在开发圈子里基本上就跟前几年的股票和基金一样,楼下摆摊卖酱香饼的阿姨都能说上几句那种。找过前端开发工作或者正在找开发工作的前端都知道,面试官基本上都有那么几个常问的问题,而网上呢也有那么一套可以用......
  • JAVA计算机毕业设计基于springboot的在线考试系统(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的快速发展和普及,教育领域对信息技术的应用越来越广泛。在线考试系统作为教育信息化的一种重要形式,已经逐渐成为了现代教育管理的重要组......
  • 排队免单,买单返现,2+1连动营销小程序源码学习使用下载。
    在当下数字化与智能化高速发展的时代,各类创新型的商业模式层出不穷,其中排队免单系统和买单返现系统便是颇具吸引力的两种商业模式。这两种系统不仅提升了消费者的购物体验,还为企业带来了更多的商业机会和收益。本文将详细解析排队免单系统和买单返现系统的运作原理、优势以......
  • javaSwing+JDBC+mysql校园跑管理项目(附源码下载)
    1.数据准备DELETEFROMstudents;Deletefromrunning;INSERTINTOstudents(student_id,name,age,major,grade)VALUES(1,'王小明',20,'计算机科学与技术','男'),(2,'张小红',21,'软件工程','女'),(3......
  • C和C++内存管理
    C和C++的内存管理C/C++中程序内存区域的划分C语言中动态内存管理方式C++中动态内存管理方式new和delete操作内置类型new和delete操作自定义类型operratornew函数和operatordelete函数new和delete的实现原理内置类型自定义类型new的原理delete的原理newT[N]的原理dele......
  • CCF-GESP 等级考试 2024年3月认证C++一级真题解析
    2024年03月真题1单选题第1题C++表达式(3-2)*3+5的值是()。A.-13B.8C.2D.0正确答案:B.8解析:首先计算括号中的表达式(3-2),得到(1)。接下来进行乘法运算(1*3),得到(3)。最后进行加法运算(3+5),得到(8)。因此,表达式的值是(8)。第2题C++......
  • CCF-GESP 等级考试 2024年3月认证C++一级真题
    2024年03月真题1单选题第1题C++表达式(3-2)*3+5的值是()。A.-13B.8C.2D.0第2题C++语句cout<<"5%2="<<5%2执行后的输出是()。A.22B.11C.5%2=2D.5%2=1第3题执行C++语句cin>>a时如果输入5+2,下述说法正确的是()。A.变量a将被......
  • 数据结构第一篇【探究List和ArrayList之间的奥秘 】
    数据结构第一篇【探究List和ArrayList之间的奥秘】前言List什么是List?ListArrayListArrayList使用ArrayList常见操作ArrayList的遍历ArrayList的扩容机制ArrayList的具体使用前言......
  • 【计算机毕业设计】基于SSM+Vue的校园美食交流系统【源码+lw+部署文档】
    目录前 言第1章概述1.1研究背景1.2研究目的1.3研究内容      第二章开发技术介绍2.1Java技术2.2Mysql数据库2.3B/S结构2.4SSM框架第三章系统分析3.1可行性分析3.1.1 技术可行性3.1.2经济可行性3.1.3操作可行性3.2系统性能分析3.3......
  • 【计算机毕业设计】基于SSM+Vue的新能源汽车在线租赁管理系统【源码+lw+部署文档】
    摘 要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,新能源汽车在线租赁当然也不能排除在外。新能源汽车在线租赁是以实际运用为开发背景,运用软件工程开发方法,采用SSM技术构建的一个管理系统。整个开发过程首先......