list实现(7)(下)

https://blog.csdn.net/qscftqwe/article/details/155534152

这是上节课的链接,大家可以看一下,好了今天我要讲的内容是关于List的正向迭代器和反向迭代器。

一.正向迭代器

cpp 复制代码
class ListIterator//正向迭代器
{
public:
	typedef Node<T> Node;
	typedef ListIterator<T, Ref, Ptr>Self;//表示自身
	ListIterator(Node* node)
		:_node(node)
	{}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &(operator *());
	}
	Self& operator++()//前置++
	{
		_node = _node->_next;
		return *this;
	}
	Self operator++(int)//后置++
	{
		Self tmp(*this);
		_node = _node->_next;
		return tmp;
	}
	Self& operator--()//前置--
	{
		_node = _node->_prev;
		return *this;
	}
	Self operator--(int)//后置
	{
		Self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	bool operator!=(const Self& it)const
	{
		return _node != it._node;
	}
	bool operator==(const Self& it)const
	{
		return _node == it._node;
	}
public:
	Node* _node;
};

关于List正向迭代器的实现其实并不复杂,关键在于理解为什么要单独封装成类,这与vector的情况有所不同。

迭代器是否需要封装主要取决于其移动方式:当迭代器的++/--操作与指针的++/--行为不一致时,就需要进行封装。

vector之所以不需要封装迭代器,是因为它的元素在内存中是连续存储的,指针的++操作正好对应着向后移动到下一个元素。

而List则不同,它的元素在内存中是分散存储的,需要通过指针跳转到下一个节点位置。这种非连续的移动方式无法通过简单的指针++实现,因此必须进行专门的封装。

二.反向迭代器

cpp 复制代码
#pragma once
template<typename Iterator, class Ref, class Ptr>
struct reverse_iterator
{
	typedef reverse_iterator<Iterator, Ref, Ptr> Self;
	reverse_iterator(Iterator it)
		:_it(it)
	{}
	Ref operator*()
	{
		Iterator tmp = _it;
		return *(--tmp);
	}
	Ptr operator->()
	{
		return &(operator*());
	}
	Self& operator++()
	{
		--_it;
		return *this;
	}
	Self operator++(int)
	{
		Self tmp(*this);
		--_it;
		return tmp;
	}
	Self& operator--()
	{
		++_it;
		return *this;
	}
	Self operator--(int)
	{
		Self tmp(*this);
		++_it;
		return tmp;
	}
	bool operator!=(const Self& it)const
	{
		return _it != it._it;
	}
	bool operator==(const Self& it)const
	{
		return _it == it._it;
	}
public://该public无作用,主要是标注下面是成员变量
	Iterator _it;
};

反向迭代器本质上是对正向迭代器的封装,它在正向迭代器的基础上增加了一层逻辑。具体来说,反向迭代器通过重载运算符实现逆向遍历功能------例如,反向迭代器的++操作实际上调用的是正向迭代器的--操作。

三.获取迭代器的方法

为什么我要讲这个呢,因为List获取迭代器的函数它可能和大家想象的不太一样!

cpp 复制代码
iterator begin()
{
	return _head->_next;
}
iterator end()
{
	return _head;
}

就是正向迭代器的begin是第一个节点,end是哨兵位(头节点)!

四.完整代码

cpp 复制代码
#pragma once
#include<assert.h>
#include"reverse_iterator.h"
#include <cstddef>   
#include <utility>  
template<class T>
class Node//节点属性
{
public:
	Node(const T& data = T())
		:_data(data)
		,_next(nullptr)
		,_prev(nullptr)
	{}
public:
	T _data;//节点的数据
	Node<T>* _next;//下一个节点
	Node<T>* _prev;//上一个节点
};

template<class T,class Ref,class Ptr>
class ListIterator//正向迭代器
{
public:
	typedef Node<T> Node;
	typedef ListIterator<T, Ref, Ptr>Self;//表示自身
	ListIterator(Node* node)
		:_node(node)
	{}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &(operator *());
	}
	Self& operator++()//前置++
	{
		_node = _node->_next;
		return *this;
	}
	Self operator++(int)//后置++
	{
		Self tmp(*this);
		_node = _node->_next;
		return tmp;
	}
	Self& operator--()//前置--
	{
		_node = _node->_prev;
		return *this;
	}
	Self operator--(int)//后置
	{
		Self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	bool operator!=(const Self& it)const
	{
		return _node != it._node;
	}
	bool operator==(const Self& it)const
	{
		return _node == it._node;
	}
public:
	Node* _node;
};

template<class T>
class List
{
	typedef ListIterator<T, T&, T*> iterator;
	typedef ListIterator<T, const T&, const T*> const_iterator;
	typedef reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
	typedef reverse_iterator<iterator, T&, T*> reverse_iterator;
	typedef Node<T> Node;//把类模板声明一下更好写
public:
	iterator begin()
	{
		return _head->_next;
	}
	iterator end()
	{
		return _head;
	}
	const_iterator begin()const
	{
		return _head->_next;
	}
	const_iterator end()const
	{
		return _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()//无参构造
		:_head(new Node)
		,_sz(0)
	{
		//首尾相连,符合双链表的形态
		_head->_next = _head;
		_head->_prev = _head;
	}
	List(const List<T>& lt)
	{
		//首尾相连,符合双链表的形态
		_head = new Node;
		_head->_next = _head;
		_head->_prev = _head;
		for (auto& e : lt)
		{
			push_back(e);
		}
	}
	~List()
	{
		clear();//清除
		delete _head;
		_head = nullptr;
		_sz = 0;
	}
	bool empty()const//判断链表是否为空
	{
		return _sz == 0;
	}
	void push_back(const T& data = T())
	{
		Node* newNode = new Node(data);//创建一个节点
		Node* tailNode = _head->_prev;
		
		//构建新节点和尾节点的链接
		newNode->_prev = tailNode;
		tailNode->_next = newNode;

		//构建新节点和头节点的链接
		newNode->_next = _head;
		_head->_prev = newNode;
		
		_sz++;

	}
	void pop_back()
	{
		assert(!empty());//不能为空
		Node* tailNode = _head->_prev;//尾节点
		Node* tailPrevNode = tailNode->_prev;//尾节点的上一个节点

		//构建尾节点的上一个节点和头节点的链接
		tailPrevNode->_next = _head;
		_head->_prev = tailPrevNode;
		
		delete tailNode;//删除尾节点
		_sz--;
	}
	void push_front(const T& data = T())
	{
		Node* newNode = new Node(data);
		Node* firstNode = _head->_next;//第一个节点

		//构建第一个节点和新节点的链接
		newNode->_next = firstNode;
		firstNode->_prev = newNode;

		//构建新节点和头节点的链接
		_head->_next = newNode;
		newNode->_prev = _head;
		_sz++;
	}
	void pop_front()
	{
		assert(!empty());//不能为空
		Node* firstNode = _head->_next;
		Node* secondNode = firstNode->_next;//第二个节点
		//构建第二个节点和头节点的关系
		secondNode->_prev = _head;
		_head->_next = secondNode;
		_sz--;
		delete firstNode;
	}
	iterator insert(iterator pos, const T& data = T())
	{
		Node* cur = pos._node;//要插入节点的位置
		Node* prev = cur->_prev;//要插入节点的上一个位置
		Node* newNode = new Node(data);

		//构建新节点和要插入节点的位置链接
		newNode->_next = cur;
		cur->_prev = newNode;

		//构建新节点和要插入节点的上一个位置链接
		newNode->_prev = prev;
		prev->_next = newNode;
		_sz++;
		return iterator(newNode);//返回插入节点的迭代器
	}
	iterator erase(iterator pos)
	{
		assert(!empty());//不能为空
		assert(pos != end());//不能删哨兵位节点

		Node* cur = pos._node;//要删除节点的位置
		Node* next = cur->_next;//要删除节点的下一个位置
		Node* prev = cur->_prev;//要删除节点的上一个位置
		//构建下一个位置和上一个位置的链接
		prev->_next = next;
		next->_prev = prev;
		delete cur;
		_sz--;
		return iterator(next);//返回删除节点的下一个位置
	}
	size_t size()const
	{
		return _sz;
	}
	void clear()//清除链表上的所有节点
	{
		Node* cur = _head->_next;
		while (cur != _head)
		{
			Node* next = cur->_next;
			delete cur;
			cur = next;
		}
		//首尾相连,符合双链表的形态
		_head->_next = _head;
		_head->_prev = _head;
		_sz = 0;
	}
	void swap(List<T>& lt)
	{
		if (&lt == this)//比的是地址避免自赋
			return;
		std::swap(_head, lt._head);
		std::swap(_sz, lt._sz);
	}
	List<T>& operator=(List<T> lt)
	{
		swap(lt);
		return *this;
	}
private:
	Node* _head;//哨兵位头节点
	size_t _sz;//统计链表上节点的个数
};
cpp 复制代码
#pragma once
template<typename Iterator, class Ref, class Ptr>
struct reverse_iterator
{
	typedef reverse_iterator<Iterator, Ref, Ptr> Self;
	reverse_iterator(Iterator it)
		:_it(it)
	{}
	Ref operator*()
	{
		Iterator tmp = _it;
		return *(--tmp);
	}
	Ptr operator->()
	{
		return &(operator*());
	}
	Self& operator++()
	{
		--_it;
		return *this;
	}
	Self operator++(int)
	{
		Self tmp(*this);
		--_it;
		return tmp;
	}
	Self& operator--()
	{
		++_it;
		return *this;
	}
	Self operator--(int)
	{
		Self tmp(*this);
		++_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;
};

五.list和vector的对比

好了关于list就到这里吧,其实学习list最主要是再次帮助我们理解迭代器相关的知识!

相关推荐
jwybobo20072 小时前
redis7.x源码分析:(9) 内存淘汰策略
linux·c++·redis
yaoxin5211232 小时前
263. Java 集合 - 遍历 List 时选用哪种方式?ArrayList vs LinkedList
java·开发语言·list
阿拉伯柠檬2 小时前
实现一个异步操作线程池
开发语言·数据结构·c++·面试
2301_803554522 小时前
Qt禁止子线程直接操作GUI
c++
羑悻的小杀马特2 小时前
C++与Redis高效交互:通过optional与迭代器玩转String/List/Set......,打造高性能存储方案!
c++·redis·交互
+++.3 小时前
c++雪花屏(vsCode+cmake+mingw+ninja)
开发语言·c++·vscode
小年糕是糕手3 小时前
【C++】内存管理(下)
java·c语言·开发语言·数据结构·c++·算法
一叶之秋14123 小时前
深入剖析vector的底层实现原理
c++
艾莉丝努力练剑3 小时前
【Linux基础开发工具 (六)】Linux中的第一个系统程序——进度条Linux:详解回车、换行与缓冲区
java·linux·运维·服务器·c++·centos