C++ STL:list的使用方法和模拟实现

目录

一. list类的简介

二. list类的使用方法

2.1 构造函数的使用

2.2 迭代器相关函数的使用

2.3 容量相关函数的使用

2.4 增删查改相关函数的使用

2.5 其余操作函数

三. list的模拟实现

3.1 链表节点和list成员变量

3.2 构造函数的模拟实现

3.3 析构函数的模拟实现 

3.4 数据插入和删除相关函数的模拟实现

3.5 链表数据量相关函数的模拟实现

3.6 正向迭代器的模拟实现

3.7 反向迭代器的模拟实现

附录:list的模拟实现完整代码


一. list类的简介

list,是C++标准类模板中提供的带头双向循环链表的数据结构容器,其抽象结构图如1.1所示。相比于单链表每个节点只存储一个指向后一个节点的指针,带头双向链表首先会有一个哨兵卫头结点(不存储任何有效数据),而且每个节点中还会有一个向前的指针。list最大的优势在于:可以在O(1)的时间复杂度内,删除任意节点的数据。

C++ STL:list的使用方法和模拟实现_第1张图片 图1.1  带头双向循环链表(list)的抽象结构图

二. list类的使用方法

2.1 构造函数的使用

有四种常用的构造函数重载形式:

  1. 默认构造函数:创建仅包含哨兵卫头结点的list对象 -- explicit list()
  2. 使用n个特定值进行初始化 -- explicit list(size_t n, const T& val = T())
  3. 使用一段迭代器区间初始化 -- list(InputIterator first, InputIterator last)
  4. 拷贝构造 -- list(const list& x)

演示代码2.1:

int main()
{
	list lt1();  //构造空链表
	list lt2(3, 6);   //构造出含有3个6的链表

	int arr[5] = { 1,2,3,4,5 };
	list lt3(arr, arr + 5);   //使用迭代器区间初始化

	list lt4(lt3);  //拷贝构造

	return 0;
}

2.2 迭代器相关函数的使用

list类给出了四种迭代器,分别为:

  1. iterator:对于普通对象的正向迭代器。
  2. const_iterator:对于const属性对象的正向迭代器。
  3. reverse_iterator:对于普通对象的反向迭代器。
  4. const_reverse_iterator:对于const属性对象的反向迭代器。

list迭代器涉及的函数主要有:begin、end、rbegin和rend,可用于实现list的正向和反向遍历,这四个函数的返回值可以理解为节点指针,指向位置见图2.1。但是,其在STL源码中被实现为了类,这样做的原因是list节点在内存中并不是连续分布的,指向++或--等操作无法找到下一个节点,但在类中就可以通过运算符重载找到下一个节点,同时,对iterator迭代器进行类封装也有利于反向迭代器的实现,第三章模拟实现会对此进行详解。

C++ STL:list的使用方法和模拟实现_第2张图片 图2.1 迭代器函数返回值指向示意图

演示代码2.2:

int main()
{
	int arr[5] = { 1,2,3,4,5 };
	list lt1(arr, arr + 5);   //使用迭代器区间初始化

	//正向迭代遍历
	list::iterator it = lt1.begin();
	while (it != lt1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	//反向迭代遍历
	list::reverse_iterator rit = lt1.rbegin();
	while (rit != lt1.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	return 0;
}
C++ STL:list的使用方法和模拟实现_第3张图片 图2.2 演示代码2.2的运行结果

2.3 容量相关函数的使用

  • empty:判断当前链表是否为空 -- bool empty()
  • size:获取链表中存储数据个数 -- size_t size()
  • resize:删除数据、添加n-size个特定数据 -- void resize(size_t n, const T& val = T())

演示代码2.3 :

int main()
{
	list lt1;  //空链表
	list lt2(10, 5);  //含有10个5

	cout << "Is list1 empty: " << lt1.empty() << endl;
	cout << "Is list2 empty: " << lt2.empty() << endl;   //链表1、2是否为空

	cout << "list1 size: " << lt1.size() << endl;
	cout << "list2 size: " << lt2.size() << endl;  //获取链表1、2中数据个数

	lt2.resize(3, 8); //将链表2中的数据删减到3个
	cout << "size of list2 after resize: " << lt2.size() << endl;

	lt2.resize(5, 1);  //将链表2的数据扩大到5个
	for (auto e : lt2)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}
C++ STL:list的使用方法和模拟实现_第4张图片 图2.3  演示代码2.3的运行结果

2.4 增删查改相关函数的使用

头插、头删、尾插、尾删

  • push_front:头插数据函数 -- void push_front(const T& val)
  • pop_front:头删数据函数 -- void pop_front()
  • push_back:尾插数据函数 -- void push_back(const T& val)
  • pop_back:尾删数据函数 -- void pop_back()

注意:使用pop_front和pop_back函数时,一定要保证链表不为空,否则程序会崩溃报错。

演示代码2.4:

int main()
{
	list lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);  //尾插数据函数

	lt.push_front(1);
	lt.push_front(2);
	lt.push_front(3);  //头插数据函数

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	lt.pop_back();  //尾删数据函数
	lt.pop_front();  //头删数据函数

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}
C++ STL:list的使用方法和模拟实现_第5张图片 图2.4 演示代码2.4的运行结果

在特定位置插入或删除数据 

  • insert:在pos位置处插入特定数据并返回指向新插入节点的迭代器 -- iterator insert(iterator pos, const T& val)
  • erase:删除特定位置pos处的数据,并返回指向原先链表中pos下一个节点位置的迭代器 -- iterator erase(iterator pos)

insert函数和pos函数一般配合find函数使用来找到插入或删除数据的位置。

C++ STL:list的使用方法和模拟实现_第6张图片 图2.5  使用insert函数插入数据之前和之后的链表结构及函数返回值指向示意图

 

C++ STL:list的使用方法和模拟实现_第7张图片 图2.6  使用erase函数删除函数之前和之后的链表结构及函数返回值指向示意图

演示代码2.5:

int main()
{
	list lt;

	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);  
	lt.push_back(4);
	lt.push_back(5);  //尾插数据

	list::iterator pos = find(lt.begin(), lt.end(), 2);
	pos = lt.insert(pos, 10);
	pos = lt.insert(pos, 20);  //在pos之前插入数据

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	pos = lt.erase(pos);
	pos = lt.erase(pos);   //删除pos位置处的数据

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}
C++ STL:list的使用方法和模拟实现_第8张图片 图2.7  演示代码2.5的运行结果

 删除特定数据

  • remove:删除特定值的数据 -- void remove(const T& val)
  • remove_if:删除满足特定条件的数据 -- void remove_if(条件判断函数)

演示代码2.6:

bool isOdd(const int& val)
{
	return val % 2 == 1;
}

int main()
{
	list lt1;

	lt1.push_back(1);
	lt1.push_back(2);
	lt1.push_back(1);
	lt1.push_back(3);
	lt1.push_back(5);  //尾插数据

	//remove函数 -- 删除链表中的特定值
	lt1.remove(1);   
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	//remove_if函数 --删除链表中满足特定条件的值
	list lt2;
	lt2.push_back(1);
	lt2.push_back(2);
	lt2.push_back(3);
	lt2.push_back(4);

	lt2.remove_if(isOdd);  //删除奇数
	for (auto e : lt2)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}
C++ STL:list的使用方法和模拟实现_第9张图片 图2.8 演示代码2.6的运行结果

2.5 其余操作函数

  • unique:删除排序链表中的重复元素,保证每个数据仅出现一次 -- void unique()
  • sort:使链表有序(默认排升序) -- void sort()
  • reverse:链表逆置 -- void reverse()

演示代码2.7:

int main()
{
	list lt1;
	lt1.push_back(1);
	lt1.push_back(5);
	lt1.push_back(2);
	lt1.push_back(2);
	lt1.push_back(8);
	lt1.push_back(8);

	lt1.sort();  //排升序
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	lt1.unique();  //去除重复元素
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	lt1.reverse();  //逆置
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}
C++ STL:list的使用方法和模拟实现_第10张图片 图2.9  演示代码2.7的运行结果

三. list的模拟实现

3.1 链表节点和list成员变量

首先,模拟实现list类应当定义出链表的节点,这里将链表的节点定义为struct类型的结构体/类,其中包含3个成员变量,分别为:

  1. _data:节点数据。
  2. _next:指向后一个节点的指针。
  3. _prev:指向前一个节点的指针。

还包含一个默认构造函数,将prev指针和next指针都初始化为nullptr。在list类中,将链表节点类型重命名为Node,list仅有一个成员变量:Node _head -- 链表头结点。

双向链表节点ListNode的定义:

    template 
	struct ListNode
	{
		T _data;  //节点数据
		ListNode* _next;  //指向下一个节点的指针
		ListNode* _prev;  //指向前一个节点的指针

		ListNode(const T& x = T())
			: _next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{ }
	};

在list类中,链表节点被类型重定义为Node:typedef ListNode Node; 

3.2 构造函数的模拟实现

  • 默认构造函数:创建哨兵卫头结点即可。
  • 迭代器区间初始化函数:创建哨兵卫头结点,然后将迭代器区间内的数据依次尾插到链表中。
  • 拷贝构造函数:通过迭代器区间,创建与被拷贝的list对象相同的临时对象tmp,然后交换_head和tmp._head,这样临时对象在生命周期结束时,就会通过析构函数释放掉原来链表节点的空间。
		explicit list()  //构造空链表
		{
			//创建哨兵卫头结点
			_head = new Node;  //节点获取
			_head->_next = _head;
			_head->_prev = _head;
		}

		//使用迭代器区间初始化
		template 
		explicit list(InputIterator first, InputIterator last)
		{
			//1.开辟哨兵卫头结点
			_head = new Node;  
			_head->_next = _head;
			_head->_prev = _head;

			//2.将迭代器区间中的数据依次尾插到链表中
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		explicit list(const list& lt)  //拷贝构造函数
		{
			//1.开辟哨兵卫头结点
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;

			//2.使用迭代器区间,构造一份与lt相同的临时对象
			list tmp(lt.begin(), lt.end());

			//3.交换*this和tmp中头结点的指向位置
			std::swap(_head, tmp._head);
		}

3.3 析构函数的模拟实现 

  • clear -- 资源清理函数:释放掉链表中出哨兵卫头结点以外的所有节点。
  • 析构函数:先调用clear函数释放存储数据的节点,然后再释放哨兵卫头结点,并将_head置为nullptr。
		void clear()  //清理链表中所有存储有效数据的节点
		{
			Node* cur = _head->_next;
			while (cur != _head)
			{
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
		}

		~list()
		{
			clear();  //调用clear函数清理除头结点以外的节点

			delete _head;  //释放哨兵卫头结点
			_head = nullptr;
		}

3.4 数据插入和删除相关函数的模拟实现

  • insert函数:首先创建一个存储有数据x的节点,找到pos位置的前一个节点prev,insert函数应当在prev和pos节点之间插入新节点,那么应当prev节点后接新节点,新节点前接prev,新节点后接pos,pos前接新节点。 
  • erase函数:首先检查要删除的pos位置是否为哨兵卫头结点,如果是,则断言报错,如果不是,则释放pos处的节点,然后链接pos前面位置和后面位置处的节点。
		iterator insert(iterator pos, const T& x)  //在pos位置之前插入数据
		{
			Node* node = pos.GetNode();
			Node* prev = node->_prev;  //在prev和node之间插入数据即可

			Node* newNode = new Node(x);
			prev->_next = newNode;
			newNode->_prev = prev;
			newNode->_next = node;
			node->_prev = newNode;

			return iterator(newNode);
		}

		iterator erase(iterator pos)  //删除pos位置处的函数
		{
			Node* del = pos.GetNode();  //要删除的节点
			assert(del != _head);  //保证哨兵卫头结点不能被删除

			Node* prev = del->_prev;
			Node* next = del->_next;  //被删除del节点的前后节点

			//删除del节点,prev节点与next节点相连
			delete del;
			del = nullptr;

			prev->_next = next;
			next->_prev = prev;

			return iterator(next);
		}

这样,尾插数据函数push_back和头插数据函数push_front就可以通过复用insert函数 来实现,同理,尾删数据函数pop_back和头删pop_front函数则可以通过复用erase函数来实现。

  • push_back:在头结点end()前插入数据。
  • push_front:在第一个存储有效数据的节点begin()前插入数据。
  • pop_back:删除--end()处的数据。
  • pop_front:删除begin()处的数据。

注意:模拟实现pop_back和pop_front函数时,要先断言链表不为空。

		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;*/

			insert(end(), x);
		}

		void push_front(const T& x)  //头插数据函数
		{
			insert(begin(), x);
		}

		bool empty()
		{
			return _head->_next == _head;
		}
		
		void pop_back()  //尾删数据函数
		{
			assert(!empty());
			erase(--end());   //--end()返回尾结点
		}

		void pop_front()  //头删数据函数
		{
			assert(!empty());
			erase(begin());   //begin返回第一个存储有效数据节点的位置
		}

3.5 链表数据量相关函数的模拟实现

  • size函数:依次遍历链表除哨兵卫头结点的每个节点,统计遍历到的节点个数并返回。
  • resize函数:给定参数n,将链表数据删除到n个,或者将链表数据扩大到n个,并将新增的节点的值初始化为x。resize函数首先应当检查size是否大于n,如果大于,就是否从第n+1个节点到尾结点的全部节点,如果n>=size,则尾插数据。
		size_t size()  //获取链表中存储有效数据的节点个数
		{
			size_t count = 0;

			Node* cur = cur->_next;
			while (cur != _head)
			{
				++count;
				cur = cur->_next;
			}

			return count;
		}

		void resize(size_t n, const T& x = T())  //删除节点 或 以数个值为x的节点延长链表
		{
			size_t i = 0;

			//找到链表的第n + 1个节点或尾结点
			Node* cur = _head->_next;
			for (i = 0; i < n; ++i)
			{
				if (cur == _head)
					break;
				
				cur = cur->_next;
			}

			if (cur != _head)
			{
				//节点的个数大于n个,要删除从cur往后的所有节点
				iterator it = iterator(cur);
				while (it != _head)
				{
					it = erase(it);
				}
			}
			else
			{
				//原链表中的节点大于或等于n个
				for (size_t j = i; j < n; ++j)
				{
					//尾插数据到含有n个节点
					push_back(x);
				}
			}
		}

3.6 正向迭代器的模拟实现

由于链表中每个节点在内存中不是连续分布的,所以,如果简单地将迭代器定义为链表节点ListNode的原生指针,那么++和--操作就不能实现找到后一个节点和前一个节点的目的,同时,解引用操作也就不能获取节点中的数据。

C++类对象支持运算符重载函数,因此,我们可以将迭代器封装到一个名为__list_iterator的类中。__list_iterator类通过类模板,可以同时应用于普通对象和const对象,其中仅包含一个成员变量_node,为链表节点的指针。同时,其中还重载了多个运算符。

在class list中,还存在着下面的类型重定义:

  • typedef __list_iterator iterator;
  • typedef __list_iterator const_iterator;

这里要特别注意->运算符的重载,Ref operator->()当且仅当T表示自定义类型数据时才有意义,假设迭代器为it,理论上的结构体成员访问应当为 it->->(结构体成员变量),但编译器对此进行了优化,只需要 it->(结构体成员变量) 即可。

	template 
	class __list_iterator
	{
		typedef ListNode Node;
		typedef __list_iterator self;

	public:
		__list_iterator(Node* node)
			: _node(node)
		{ }
		
		Node* GetNode()
		{
			return _node;
		}

		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  //不等判断函数
		{
			return _node != it._node;
		}

		bool operator==(const self& it) const   // 相对判断函数
		{
			return _node == it._node;
		}

	private:
		Node* _node;  //成员变量 -- 节点的地址
	};

在class类中,还对begin()、end()进行了定义,begin()返回第一个存储了数据的节点,end()返回头节点。

		typedef __list_iterator iterator;
		typedef __list_iterator const_iterator;

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

		iterator end()
		{
			return _head;
		}

		const_iterator begin() const
		{
			return _head->_next;
		}

		const_iterator end() const
		{
			return _head;
		}

3.7 反向迭代器的模拟实现

反向迭代器,是在正向迭代器的基础之上实现的,其也被封装到了一个名为reverse_iterator的类中,这个类中也只有一个成员变量:_it -- 类型为整形迭代器。

  • ++运算符重载函数:调用正向迭代器的--即可。
  • --运算符重载函数:调用正向迭代器的++即可。
  • ==和!=运算符重载函数:晕正向迭代器的实现完全一致。
  • *运算符重载函数:需要特别注意,返回的是_it成员前一个位置的解引用值,这是因为rbegin并不是最后一个节点,rend也不是头结点,而是rbegin=end(),rend=begin()。
	template
	class reverse_iterator
	{
		typedef reverse_iterator self;

	public:
		reverse_iterator(Iterator it)  //构造函数
			: _it(it)
		{ }

		Ref operator*()  //解引用函数重载
		{
			Iterator prev = _it;
			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;
		}

	private:
		Iterator _it;  //正向迭代器
	};

class list中对rend和rbegin的定义:

typedef reverse_iterator  const_reverse_iterator;
typedef reverse_iterator reverse_iterator;

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());
}

附录:list的模拟实现完整代码

//reverse_iterator.h文件
#pragma once
namespace zhang
{
	template
	class reverse_iterator
	{
		typedef reverse_iterator self;

	public:
		reverse_iterator(Iterator it)  //构造函数
			: _it(it)
		{ }

		Ref operator*()  //解引用函数重载
		{
			Iterator prev = _it;
			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;
		}

	private:
		Iterator _it;  //正向迭代器
	};
}

//list.h文件
#pragma once
#include
#include
#include "reverse_iterator.h"

namespace zhang
{
	template 
	struct ListNode
	{
		T _data;  //节点数据
		ListNode* _next;  //指向下一个节点的指针
		ListNode* _prev;  //指向前一个节点的指针

		ListNode(const T& x = T())
			: _next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{ }
	};

	template 
	class __list_iterator
	{
		typedef ListNode Node;
		typedef __list_iterator self;

	public:
		__list_iterator(Node* node)
			: _node(node)
		{ }
		
		Node* GetNode()
		{
			return _node;
		}

		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  //不等判断函数
		{
			return _node != it._node;
		}

		bool operator==(const self& it) const   // 相对判断函数
		{
			return _node == it._node;
		}

	private:
		Node* _node;  //成员变量 -- 节点的地址
	};

	template 
	class list
	{
	public:
		typedef ListNode Node;
		typedef __list_iterator iterator;
		typedef __list_iterator const_iterator;
		
		typedef reverse_iterator const_reverse_iterator;
		typedef reverse_iterator reverse_iterator;

		explicit list()  //构造空链表
		{
			//创建哨兵卫头结点
			_head = new Node;  //节点获取
			_head->_next = _head;
			_head->_prev = _head;
		}

		//使用迭代器区间初始化
		template 
		explicit list(InputIterator first, InputIterator last)
		{
			//1.开辟哨兵卫头结点
			_head = new Node;  
			_head->_next = _head;
			_head->_prev = _head;

			//2.将迭代器区间中的数据依次尾插到链表中
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		explicit list(const list& lt)  //拷贝构造函数
		{
			//1.开辟哨兵卫头结点
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;

			//2.使用迭代器区间,构造一份与lt相同的临时对象
			list tmp(lt.begin(), lt.end());

			//3.交换*this和tmp中头结点的指向位置
			std::swap(_head, tmp._head);
		}

		//赋值函数
		list& operator=(list lt)
		{
			std::swap(_head, lt._head);
			return *this;
		}

		void clear()  //清理链表中所有存储有效数据的节点
		{
			Node* cur = _head->_next;
			while (cur != _head)
			{
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
		}

		~list()
		{
			clear();  //调用clear函数清理除头结点以外的节点

			delete _head;  //释放哨兵卫头结点
			_head = nullptr;
		}

		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());
		}

		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;*/

			insert(end(), x);
		}

		void push_front(const T& x)  //头插数据函数
		{
			insert(begin(), x);
		}

		bool empty()
		{
			return _head->_next == _head;
		}
		
		void pop_back()  //尾删数据函数
		{
			assert(!empty());
			erase(--end());   //--end()返回尾结点
		}

		void pop_front()  //头删数据函数
		{
			assert(!empty());
			erase(begin());   //begin返回第一个存储有效数据节点的位置
		}

		iterator insert(iterator pos, const T& x)  //在pos位置之前插入数据
		{
			Node* node = pos.GetNode();
			Node* prev = node->_prev;  //在prev和node之间插入数据即可

			Node* newNode = new Node(x);
			prev->_next = newNode;
			newNode->_prev = prev;
			newNode->_next = node;
			node->_prev = newNode;

			return iterator(newNode);
		}

		iterator erase(iterator pos)  //删除pos位置处的函数
		{
			Node* del = pos.GetNode();  //要删除的节点
			assert(del != _head);  //保证哨兵卫头结点不能被删除

			Node* prev = del->_prev;
			Node* next = del->_next;  //被删除del节点的前后节点

			//删除del节点,prev节点与next节点相连
			delete del;
			del = nullptr;

			prev->_next = next;
			next->_prev = prev;

			return iterator(next);
		}

		size_t size()  //获取链表中存储有效数据的节点个数
		{
			size_t count = 0;

			Node* cur = cur->_next;
			while (cur != _head)
			{
				++count;
				cur = cur->_next;
			}

			return count;
		}

		void resize(size_t n, const T& x = T())  //删除节点 或 以数个值为x的节点延长链表
		{
			size_t i = 0;

			//找到链表的第n + 1个节点或尾结点
			Node* cur = _head->_next;
			for (i = 0; i < n; ++i)
			{
				if (cur == _head)
					break;
				
				cur = cur->_next;
			}

			if (cur != _head)
			{
				//节点的个数大于n个,要删除从cur往后的所有节点
				iterator it = iterator(cur);
				while (it != _head)
				{
					it = erase(it);
				}
			}
			else
			{
				//原链表中的节点大于或等于n个
				for (size_t j = i; j < n; ++j)
				{
					//尾插数据到含有n个节点
					push_back(x);
				}
			}
		}

		void Print()
		{
			iterator it = begin();
			while (it != end())
			{
				std::cout << *it << " ";
				++it;
			}
			std::cout << std::endl;
		}

	private:
		Node* _head;
	};
}

你可能感兴趣的:(C++从入门到精通,c++,链表,开发语言)