C++之List的模拟实现以及List反转迭代器的构建

一.List介绍

list的底层是双向循环链表,可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代,与其他底层是顺序表的容器(vector,array,deque)相比,list在任意位置进行插入,移除元素更加高效;但是和这些底层是顺序表的容器相比,list最大的缺陷就是不支持任意位置的随机访问。

C++之List的模拟实现以及List反转迭代器的构建_第1张图片

二.成员变量

	public:
		Node* node;

list的成员变量只有一个节点类型的指针,它指向该双向循环链表的虚拟头节点。

二.list构造函数

C++之List的模拟实现以及List反转迭代器的构建_第2张图片

		//无参构造函数
        list()
		{
			head = new Node();
			head->next = head;
			head->prev = head;
		}
		//利用模板函数以及迭代器来构造对象
		template
		list(Inputiterator first, Inputiterator last)
		{
			head = new Node();
			head->next = head;
			head->prev = head;
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		//深拷贝的拷贝构造函数,现代写法
		list(const list& x)
		{
			head = new Node();
			head->next = head;
			head->prev = head;
			list tmp(x.begin(), x.end());
			std::swap(head, tmp.head);
		}

注意:List的每一个构造函数都需要创建虚拟头节点 

 三.list iterator的使用:begin,end,rbegin,rend函数

3.1函数功能

C++之List的模拟实现以及List反转迭代器的构建_第3张图片

C++之List的模拟实现以及List反转迭代器的构建_第4张图片

C++之List的模拟实现以及List反转迭代器的构建_第5张图片 3.2代码实现

//取头节点的迭代器
		iterator begin()
		{
			return iterator(head->next);
		}

		const_iterator begin() const
		{
			return const_iterator(head->next);
		}

		//以最后一个元素的下一个位置的迭代器构造的_revese_iterator作为返回值,就是用正向迭代器模拟实现反向迭代器,这是一种复用的表现,可以减少代码量
		_revese_iterator rbegin()
		{
			return _revese_iterator(end());
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		//取尾节点(虚拟头节点)的迭代器
		iterator end()
		{
			return iterator(head);
		}

		const_iterator end() const
		{
			return const_iterator(head);
		}

		//以第一个元素的迭代器构造的_revese_iterator作为返回值,就是用正向迭代器模拟实现反向迭代器,这是一种复用的表现,可以减少代码量
		_revese_iterator rend()
		{
			return _revese_iterator(begin());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

 上面的_reverse_iterator反向迭代器是由正向迭代器构造实现的,这是一种设计模式,是一种复用的表现,可以减少代码量。

四.List类正向迭代器

4.1.list类迭代器的作用

利用List对象里的节点构造出迭代器,然后就可以使用该迭代器来遍历List对象中的每一个节点,实现解引用迭代器对象来完成取节点中的值的操作,还可以通过++,--来实现List对象中节点的遍历,list类迭代器本质上也是一个类,一个可以完成List对象中节点遍历的类。

4.2.成员变量

list的成员变量只有一个节点类型的指针,它指向该双向循环链表的虚拟头节点。

	public:
		Node* node;

 4.3.代码实现

	template
	class __list_iterator
	{
	public:
		typedef ListNode Node;
		typedef __list_iterator self;
		__list_iterator(Node* x)
			:node(x)
		{
		}
		//解引用运算符重载
		Ref operator*()
		{
			return node->data;
		}
		//-> 迭代器是借助节点的指针访问修改链表,这里表示用指针->->来获取数据,然后编译器会优化为指针->来获取数据
		Ptr operator->()
		{
			return &node->data;
		}
		//迭代器前置加加,返回加加后的迭代器
		self operator++()
		{
			node = node->next;
			return *this;
		}
		//迭代器后置加加,返回加加前的迭代器
		self operator++(int)
		{
			self tmp(node);
			node = node->next;
			return tmp;
		}
		//迭代器前置减减,返回减减后的迭代器
		self operator--()
		{
			node = node->prev;
			return *this;
		}
		//迭代器后置减减,返回减减前的迭代器
		self operator--(int)
		{
			self tmp(node);
			node = node->prev;
			return tmp;
		}

		//判断两个迭代器指向的内容是否相等
		bool operator!=(const self& it)  const
		{
			if (it.node != node)
			{
				return true;
			}
			return false;
		}

		bool operator==(const self& it)  const
		{
			return !(*this != it);
		}

	public:
		Node* node;
	};

 五.List类反向迭代器

5.1反向迭代器的介绍

它的作用是可以反向遍历List里面的每一个节点,它是由正向迭代器构造出来的,所以它所有功能都是由正向迭代器来实现的,与正向迭代器不同的是,当解引用反向迭代器的时候,取得不是当前迭代器指向的节点的值,而是取得是前一个节点的值,这是因为迭代器rend指向的是头节点,迭代器rbegin指向的是虚拟头节点。反向迭代器的--,和++操作,对应着正向迭代器的++,--操作。

5.2成员变量

public:
	_iterator it;

是一个正向迭代器 

5.3代码实现:

template
class resverse_iterator
{
public:
	typedef iterator _iterator;
	typedef resverse_iterator self;
	resverse_iterator(const _iterator& x)
		:it(x)
	{
	}
	//解引用运算符重载
	Ref operator*()
	{
		_iterator prev = it;
		return *(--prev);
	}
	//-> 迭代器是借助节点的指针访问修改链表,这里表示用指针->->来获取数据,然后编译器会优化为指针->来获取数据
	Ptr operator->()
	{
		_iterator prev = it;
		--prev;
		return &*(prev);
	}
	//迭代器前置加加,返回加加后的迭代器
	self operator++()
	{
		--it;
		return *this;
	}
	//迭代器后置加加,返回加加前的迭代器
	self operator++(int)
	{
		self tmp(it);
		--it;
		return tmp;
	}
	//迭代器前置减减,返回减减后的迭代器
	self operator--()
	{
		++it;
		return *this;
	}
	//迭代器后置减减,返回减减前的迭代器
	self operator--(int)
	{
		self tmp(it);
		++it;
		return tmp;
	}

	//判断两个迭代器指向的内容是否相等
	bool operator!=(const self& It)  const
	{
		return it != It.it;
	}

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

public:
	_iterator it;
};

六.push_back函数

6.1功能

在List链表中尾插一个节点

6.2返回值

无返回值

6.3实现逻辑

(1)先在堆上申请一块空间,这块空间存放着一个新节点的值

(2)让虚拟头节点的prev指针指向新节点,尾节点的next指针指向新节点

(3)新节点的prev指向尾节点,新节点的next指向虚拟头节点

		//尾插一个元素
		void push_back(const T& val)
		{
			Node* newnode = new Node(val);
			Node* _prev = head->prev;
			_prev->next = newnode;
			newnode->prev = _prev;
			newnode->next = head;
			head->prev = newnode;
		}

6.4实现结果 

C++之List的模拟实现以及List反转迭代器的构建_第6张图片

七.erase函数

7.1功能

删除List对象中某个迭代器指向的节点,它可以是复用实现尾删,头删,以及清空List对象全部有效节点等功能

7.2返回值

返回下一个节点的迭代器

7.3实现逻辑

(1)要删除的节点的前一个节点指向要删除的节点的下一个节点

(2)释放要删除的节点的空间

		// 这里erase以后,pos是否失效?一定失效
		iterator erase(iterator pos)
		{
			assert(pos != end());
			Node* cur = pos.node;
			Node* pre = pos.node->prev;
			Node* _next = pos.node->next;
			pre->next = _next;
			_next->prev = pre;
			delete cur;
			iterator(_next);
		}
		//尾删一个元素
		void pop_back()
		{
			erase(--end());
		}

		//头删一个元素
		void pop_front()
		{
			erase(begin());
		}

		void clear()
		{
            //第一种方式:
			//list::iterator it = begin();
			//while (it != end())
			//{
			//	iterator del = it++;
			//	delete del.node;
			//}
			//head->next = head;
			//head->prev = head;
			另一种方式
			while (it != end())
			{
				erase(it++);
			}
		}

7.4实现结果 

C++之List的模拟实现以及List反转迭代器的构建_第7张图片

八.insert函数

8.1功能

在迭代器pos指向的节点后面插入一个节点

8.2返回值

返回插入的新节点的迭代器

8.3实现逻辑

(1)先在堆上申请一块空间,这块空间存放着一个新节点的值

(2)让迭代器pos指向的节点的prev指针指向新节点,迭代器pos指向的节点的前一个节点的next指针指向新节点

(3)新节点的prev指向迭代器pos指向的节点的前一个节点,新节点的next指向迭代器pos指向的节点

		// 这里insert以后,pos是否失效?一定失效
		iterator insert(iterator pos, const T& x)
		{
			Node* newnode = new Node(x);
			Node* _prev = pos.node->prev;
			_prev->next = newnode;
			newnode->prev = _prev;
			newnode->next = pos.node;
			pos.node->prev = newnode;
			return iterator(newnode);
		}

8.4实现结果 

C++之List的模拟实现以及List反转迭代器的构建_第8张图片

 

你可能感兴趣的:(C++,c++,链表,开发语言)