目录
关于list
list常见接口实现
STL的精华之迭代器
关于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常见接口实现(参考部分g++版本下stl底层源码)
namespace dw
{
	template<class T>
	struct list_node //链表节点
	{
		list_node<T>* _prev;
		list_node<T>* _next;
		T _data;
	};
	//迭代器实现
	template<class T>
	class list
	{
		typedef list_node<T> node;
	public:
		//代码实现
	private:
		node* _head;
	};
	//------------------------------------------------
	void list_test()
	{
		;
	}
}1.注意:类名不是类型,建议声明类型的时候都加上模板参数
举例来说这里 list_node 是类名, list_node<T> 是类型
如果不加上模板参数运行程序会报错
typedef list_node<T> node;typedef list_node node;
2.注意:这里使用的 struct 定义类,struct 定义的类默认访问权限是公开。
构造函数
无参
		void empty_init() //初始化头节点
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		list()
		{
			empty_init();
		}push_back
		void push_back(const T& x)
		{
			node* tail = _head->_prev;
			node* newnode = new node(x);
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;
		}注意,这里测试运行会发现:

原因出在:
node* newnode = new node(x);所以关于链表节点 list_node 的这个类也需要实现构造函数
		list_node(const T& x = T()) //这里是匿名对象调用构造函数
			:_prev(nullptr)
			,_next(nullptr)
			,_data(x)
		{}
STL的精华之迭代器
这样就完成了需要的准备工作,接下来就可以进行神奇的迭代器部分了,看完大呼 - 还可以这样玩。
上面的代码可以通过测试以及调试观看到具体状态,那么怎么进行成员访问?
我们知道,vector 迭代器使用的是原生指针(g++版本) vector相关迭代器的实现,因为 vector 可以看作是一块连续的物理空间,我们通过下标就可以访问到下一个元素
但是链表可以这样玩吗?肯定是不可以的!所以,这里 list 迭代器的实现不能使用原生指针,而是需要一个类去进行封装。

iterator
//迭代器实现
	template<class T>
	struct __list_iterator
	{
	public:
		typedef list_node<T> node;
		typedef __list_iterator self;
		node* _node;
		__list_iterator(node* x)
			:_node(x)
		{}
		T& operator*()
		{
			return _node->_data;
		}
		self& operator++() 
		{
			_node =  _node->_next;
			return *this;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
	};注意:c++一般不喜欢内部类,所以一般都使用自定义类型
继而我们需要在 list 类进行 typedef
typedef __list_iterator<T> iterator;begin()
begin()是第一个节点的位置
        iterator begin()
		{
			iterator tmp(_head->_next);
			return tmp;
		}
		end()
end()是头节点的位置
        iterator end()
		{
			return iterator(_head);
		}注:这里和 begin( ) 的写法其实没什么不同,本质上是运用了匿名对象。

- 其实这里可以看到,虽然vector,list 表面上都是 iterator,但是底层却千差万别,这些都源自于底层的封装
- 并且,可以明显的感觉到迭代器很好体现了类的设计价值。如果一个内置类型无法满足我们的需求,那么我们可以使用一个自定义类型去封装,然后重载运算符,继而改变它的行为
- 比如说这里的 iterator 是一个节点的指针,++, * 不满足我们的需求,我们可以去进行封装, 用类去封装一个node* 重载++, * 运算符的函数
- 重载运算符函数的具体实现以及行为完全由我们自己来定义,这是自定义类型+运算符重载+类的定义等等的价值
其次,关于下面这句代码,我们并没有实现拷贝构造,编译器会默认生成,默认生成的拷贝构造是浅拷贝,那么,这里可以使用浅拷贝嘛?为什么没报错?
list<int>::iterator it = lt.begin();//首先:这里是需要浅拷贝的,因为这里拷贝的是指向节点的指针
//其次,为什么没报错 ? 是因为迭代器没有写析构函数,那么为什么没写 ?
//是因为迭代器不需要释放节点。更深层次一些,为什么不需要释放节点 ?
//虽然这里迭代器有指向节点的指针,但是并不支持释放节点,因为释放节点是链表的行为
//链表会有析构函数释放节点,也可以简单把这里迭代器理解为工具,可以支持读或者写
//但是只有使用权限,并没有归属权限,所以这里浅拷贝也就没有问题了。
然后现在就可以丰富一些 迭代器 __list_iterator 这个类,后置 ++ ,--,等等
template<class T>
	struct __list_iterator
	{
	public:
		typedef list_node<T> node;
		typedef __list_iterator<T> self;
		node* _node;
		__list_iterator(node* x)
			:_node(x)
		{}
		T& operator*()
		{
			return _node->_data;
		}
		self& operator++()
		{
			_node =  _node->_next;
			return *this;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		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& s)
		{
			return _node == s._node;
		}
	};const_iterator
接下来是关于 const 修饰的迭代器,如果是下面这样环境,该怎么办?

这里的迭代器就需要使用const 进行修饰了,那么请问这样写法可不可以?
		iterator begin() const
		{
			iterator tmp(_head->_next);
			return tmp;
		}
		iterator end() const
		{
			return iterator(_head);
		}这里运行编译通过,但是存在一个问题,明明是const修饰,为什么还能构造迭代器?
 因为这里的const修饰的是*this 也就是指向的内容,*this 是这个节点的指针,const修饰的是这个指针的本身不能被改变,也就是_head不能被改变,但是可以拷贝。

 结果发现并不符合我们的预期,因为这里我们期望迭代器被 const 修饰之后内容不可修改。这里不仅可读,并且可写,显然程序是有些不正确的。
所以这里的写法是我们需要再完成一个类,也就是 __list_const_iterator
    template<class T>
	struct __list_const_iterator
	{
	public:
		typedef list_node<T> node;
		typedef __list_const_iterator<T> self;
		node* _node;
		__list_const_iterator(node* x)
			:_node(x)
		{}
		const T& operator*()
		{
			return _node->_data;
		}
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		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& s)
		{
			return _node == s._node;
		}
	};注意:c++一般不喜欢内部类,所以一般都使用自定义类型
继而我们需要在 list 类进行 typedef
typedef __list_const_iterator<T> const_iterator;begin()
        const_iterator begin() const
		{
			const_iterator tmp(_head->_next);
			return tmp;
		}end()
        const_iterator end() const
		{
			return const_iterator(_head);
		}代码程序正常运行

但是观察上面这两个类我们会发现,__list_iterator 与 __list_const_iterator
他们的区别只在于重载运算符解引用的实现不同,更细节一点只是解引用的返回值不同
__list_iterator

__list_const_iterator

但是却写了两个类,这样会显得代码很臃肿,会让人觉得一模一样的代码为什么要写两遍,所以这里提出了一个新的语法知识 - - - 添加模板参数
代码如下:
    template<class T, class Ref>
	struct __list_iterator
	{
	public:
		typedef list_node<T> node;
		typedef __list_iterator<T, Ref> self;
		node* _node;
		__list_iterator(node* x)
			:_node(x)
		{}
		Ref operator*()
		{
			return _node->_data;
		}
		self& operator++()
		{
			_node =  _node->_next;
			return *this;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		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& s)
		{
			return _node == s._node;
		}
	};这样 __list_iterator 与 __list_const_iterator 就可以合并为一个类

再修改一些 list ,模板参数不同,调用逻辑也不同
        typedef __list_iterator<T, T&> iterator;
		typedef __list_iterator<T, const T&> const_iterator;
		//typedef __list_const_iterator<T> const_iterator; //注释掉例:

如果你认为到这里就结束了,那么不好意思,还差一点。因为观察库里 list 的实现,我们会发现迭代器的模板参数是三个。
附上stl部分底层源码:
template<class T, class Ref, class Ptr>
struct __list_iterator {
  typedef __list_iterator<T, T&, T*>             iterator;
  typedef __list_iterator<T, const T&, const T*> const_iterator;
  typedef __list_iterator<T, Ref, Ptr>           self;
  typedef bidirectional_iterator_tag iterator_category;
  typedef T value_type;
  typedef Ptr pointer;
  typedef Ref reference;
  typedef __list_node<T>* link_type;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  link_type node;
  __list_iterator(link_type x) : node(x) {}
  __list_iterator() {}
  __list_iterator(const iterator& x) : node(x.node) {}
  bool operator==(const self& x) const { return node == x.node; }
  bool operator!=(const self& x) const { return node != x.node; }
  reference operator*() const { return (*node).data; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
  self& operator++() { 
    node = (link_type)((*node).next);
    return *this;
  }
  self operator++(int) { 
    self tmp = *this;
    ++*this;
    return tmp;
  }
  self& operator--() { 
    node = (link_type)((*node).prev);
    return *this;
  }
  self operator--(int) { 
    self tmp = *this;
    --*this;
    return tmp;
  }
};源码的 Ptr 是什么?因为这里不仅重载了*,还重载了 ->,那么什么时候要去调用->呢?
1.迭代器要么就是原生指针
 ⒉.迭代器要么就是自定义类型对原生指针的封装,模拟指针的行为
解释这个原因的话,先看一个测试用例:

这时候我们会发现,之所以会报错是因为AA这个类没有自己实现一个流插入
所以要是想让代码跑起来,有很多的解决办法
方法一便是根据AA这个类型重载一个流插入
所以回过头来也能发现,c++新增运算符重载,而不是继续使用printf函数,是因为printf函数有局限性,printf只能打印内置类型,%d,%lf等等。
但是打印也不是没有其他办法,比如说上面这种,但是看到似乎是有点怪,解引用之后﹒去访问成员
 所以这样为了看起来更顺畅一些,我们需要去实现  ->
这里返回值是T*,但是如果是const迭代器呢?
所以这里就不能使用T*,而是需要新增加函数模板参数 Ptr
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
	public:
		typedef list_node<T> node;
		typedef __list_iterator<T, Ref, Ptr> self;
		node* _node;
		__list_iterator(node* x)
			:_node(x)
		{}
		Ptr operator->()
		{
			return &_node->_data;
		}
		Ref operator*()
		{
			return _node->_data;
		}
		self& operator++()
		{
			_node =  _node->_next;
			return *this;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		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& s)
		{
			return _node == s._node;
		}
	};

以上就是list底层源码的实现逻辑,补充一点:

这里看着是有些怪异的,因为
it-> _a1
 it-> ->_a1
本来这里应该是两个 ->
一个是运算符重载的调用
一个是有了结构体的指针再使用 -> 去访问
这里为了增加代码的可读性,省略了一个-> ,可以理解为是一个特殊处理
看似是:
cout << it->_a1 << ":" << it->_a2 << endl;实际上:
cout << it.operator->()->_a1 << ":" << it.operator->()->_a2 << endl;另外需要说明的点是:
迭代器用原生指针只是一个偶然,用类去封装才是一个常态
但是底层的本质都可以认为是指针,只说是嵌入了一个自定义类型去封装指针,在编译器看来是自定义类型而不是指针
并且自定义类型使用运算符只能去重载运算符,至于重载运算符函数的行为,完全是由我们自己来控制的
包括vector的迭代器, 在g++版本下(linux系统)是原生指针,但是vs下也不是原生指针,因为vs需要重载运算符函数,比如 * 用来判断迭代器是否失效。
要注意,不同编译器底层实现不同。以上就是 stl 的精华部分,关于迭代器。
        
swap
		void swap(list<T>& tmp)
		{
			std::swap(_head, tmp._head);
		}迭代器区间构造
        template<class Iterator>
		list(Iterator first, Iterator last)
		{
			empty_init();
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}拷贝构造
        //现代写法
		list(const list<T>& lt)
		{
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}
		//传统写法
		list(const list<T>& lt)
		{
			empty_init();
			for (auto e : lt)
			{
				push_back(e);
			}
		}赋值
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}insert
		void insert(iterator pos, const T& x)
		{
			node* cur = pos._node;
			node* prev = cur->_prev;
			node* new_node = new node(x);
			prev->_next = new_node;
			new_node->_next = cur;
			new_node->_prev = prev;
			cur->_prev = new_node;
		}erase
		void erase(iterator pos)
		{
			assert(pos != end());
			node* next = pos._node->_next;
			node* prev = pos._node->_prev;
			next->_prev = prev;
			prev->_next = next;
			delete pos._node;
		}
        //看需求
        iterator erase(iterator pos)
		{
			assert(pos != end());
			node* next = pos._node->_next;
			node* prev = pos._node->_prev;
			next->_prev = prev;
			prev->_next = next;
			delete pos._node;
			return iterator(next);
		}push_front
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
pop_back
		void pop_back()
		{
			erase(--end());
		}
pop_front
		void pop_front()
		{
			erase(begin());
		}clear
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				erase(it++);
				
				//it = erase(it);  //两种方法都可以,这中 erase 需要有返回值
			}
		}析构函数
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
最后附上全部代码以及测试用例:
list.h
namespace dw
{
	template<class T>
	struct list_node //链表节点
	{
		list_node<T>* _prev;
		list_node<T>* _next;
		T _data;
		list_node(const T& x = T())
			:_prev(nullptr)
			,_next(nullptr)
			,_data(x)
		{}
	};
	//迭代器实现
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
	public:
		typedef list_node<T> node;
		typedef __list_iterator<T, Ref, Ptr> self;
		node* _node;
		__list_iterator(node* x)
			:_node(x)
		{}
		Ptr operator->()
		{
			return &_node->_data;
		}
		Ref operator*()
		{
			return _node->_data;
		}
		self& operator++()
		{
			_node =  _node->_next;
			return *this;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		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& s)
		{
			return _node == s._node;
		}
	};
	
	/*
	template<class T>
	struct __list_const_iterator
	{
	public:
		typedef list_node<T> node;
		typedef __list_const_iterator<T> self;
		node* _node;
		__list_const_iterator(node* x)
			:_node(x)
		{}
		const T& operator*()
		{
			return _node->_data;
		}
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		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& s)
		{
			return _node == s._node;
		}
	};
	*/
	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 __list_const_iterator<T> const_iterator;
		void empty_init() //初始化头节点
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		list()
		{
			empty_init();
		}
	
		void swap(list<T>& tmp)
		{
			std::swap(_head, tmp._head);
		}
		//现代写法
		list(const list<T>& lt)
		{
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}
		//传统写法
		//list(const list<T>& lt)
		//{
		//	empty_init();
		//	for (auto e : lt)
		//	{
		//		push_back(e);
		//	}
		//}
		template<class Iterator>
		list(Iterator first, Iterator last)
		{
			empty_init();
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}
		//lt2 = lt1
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}
		iterator begin() 
		{
			iterator tmp(_head->_next);
			return tmp;
		}
		iterator end() 
		{
			return iterator(_head);
		}
		const_iterator begin() const
		{
			const_iterator tmp(_head->_next);
			return tmp;
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}
		void push_back(const T& x)
		{
			node* tail = _head->_prev;
			node* newnode = new node(x);
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;
		}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pop_back()
		{
			erase(--end());
		}
		void pop_front()
		{
			erase(begin());
		}
		iterator erase(iterator pos)
		{
			assert(pos != end());
			node* next = pos._node->_next;
			node* prev = pos._node->_prev;
			next->_prev = prev;
			prev->_next = next;
			delete pos._node;
			return iterator(next);
		}
		void insert(iterator pos, const T& x)
		{
			node* cur = pos._node;
			node* prev = cur->_prev;
			node* new_node = new node(x);
			prev->_next = new_node;
			new_node->_next = cur;
			new_node->_prev = prev;
			cur->_prev = new_node;
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				erase(it++);
				
				//it = erase(it);  //两种方法都可以,这中 erase 需要有返回值
			}
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
	private:
		node* _head;
	};
	//------------------------------------------------
	void print_list(const list<int>& lt)
	{
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			//(*it) *= 2;
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}
	void list_test1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		print_list(lt);
		list<int> lt2(lt);
		for (auto e : lt2)
		{
			cout << e << " ";
		}
		cout << endl;
		list<int> lt3 = lt2;
		for (auto e : lt3)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void list_test2()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_back(5);
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
		lt.push_back(1000); //测试尾插
		lt.push_front(100); // 测试头插
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
		lt.pop_back(); // 测试尾删
		lt.pop_front(); //测试头删
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
		auto pos = lt.begin();
		++pos;
		lt.insert(pos, 9); //测试任意位置插入
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
		pos = lt.begin();
		++pos;
		lt.erase(pos); // 测试任意位置删除
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}



















![leetcode--1004 最大连续1的个数 III[滑动窗口c++]](https://img-blog.csdnimg.cn/img_convert/8359a814a22f6912b6659667cc99ac75.png)